1
0
mirror of https://github.com/bitwarden/server synced 2025-12-25 12:43:14 +00:00

Merge branch 'main' into SM-1571-DisableSMAdsForUsers

This commit is contained in:
cd-bitwarden
2025-10-23 10:00:46 -04:00
committed by GitHub
22 changed files with 717 additions and 104 deletions

View File

@@ -8,6 +8,7 @@ namespace Bit.Core.Test.Models.Data.EventIntegrations;
public class IntegrationMessageTests
{
private const string _messageId = "TestMessageId";
private const string _organizationId = "TestOrganizationId";
[Fact]
public void ApplyRetry_IncrementsRetryCountAndSetsDelayUntilDate()
@@ -16,6 +17,7 @@ public class IntegrationMessageTests
{
Configuration = new WebhookIntegrationConfigurationDetails(new Uri("https://localhost"), "Bearer", "AUTH-TOKEN"),
MessageId = _messageId,
OrganizationId = _organizationId,
RetryCount = 2,
RenderedTemplate = string.Empty,
DelayUntilDate = null
@@ -36,6 +38,7 @@ public class IntegrationMessageTests
{
Configuration = new WebhookIntegrationConfigurationDetails(new Uri("https://localhost"), "Bearer", "AUTH-TOKEN"),
MessageId = _messageId,
OrganizationId = _organizationId,
RenderedTemplate = "This is the message",
IntegrationType = IntegrationType.Webhook,
RetryCount = 2,
@@ -48,6 +51,7 @@ public class IntegrationMessageTests
Assert.NotNull(result);
Assert.Equal(message.Configuration, result.Configuration);
Assert.Equal(message.MessageId, result.MessageId);
Assert.Equal(message.OrganizationId, result.OrganizationId);
Assert.Equal(message.RenderedTemplate, result.RenderedTemplate);
Assert.Equal(message.IntegrationType, result.IntegrationType);
Assert.Equal(message.RetryCount, result.RetryCount);
@@ -67,6 +71,7 @@ public class IntegrationMessageTests
var message = new IntegrationMessage
{
MessageId = _messageId,
OrganizationId = _organizationId,
RenderedTemplate = "This is the message",
IntegrationType = IntegrationType.Webhook,
RetryCount = 2,
@@ -77,6 +82,7 @@ public class IntegrationMessageTests
var result = JsonSerializer.Deserialize<IntegrationMessage>(json);
Assert.Equal(message.MessageId, result.MessageId);
Assert.Equal(message.OrganizationId, result.OrganizationId);
Assert.Equal(message.RenderedTemplate, result.RenderedTemplate);
Assert.Equal(message.IntegrationType, result.IntegrationType);
Assert.Equal(message.RetryCount, result.RetryCount);

View File

@@ -22,18 +22,20 @@ public class EventIntegrationEventWriteServiceTests
[Theory, BitAutoData]
public async Task CreateAsync_EventPublishedToEventQueue(EventMessage eventMessage)
{
var expected = JsonSerializer.Serialize(eventMessage);
await Subject.CreateAsync(eventMessage);
await _eventIntegrationPublisher.Received(1).PublishEventAsync(
Arg.Is<string>(body => AssertJsonStringsMatch(eventMessage, body)));
body: Arg.Is<string>(body => AssertJsonStringsMatch(eventMessage, body)),
organizationId: Arg.Is<string>(orgId => eventMessage.OrganizationId.ToString().Equals(orgId)));
}
[Theory, BitAutoData]
public async Task CreateManyAsync_EventsPublishedToEventQueue(IEnumerable<EventMessage> eventMessages)
{
var eventMessage = eventMessages.First();
await Subject.CreateManyAsync(eventMessages);
await _eventIntegrationPublisher.Received(1).PublishEventAsync(
Arg.Is<string>(body => AssertJsonStringsMatch(eventMessages, body)));
body: Arg.Is<string>(body => AssertJsonStringsMatch(eventMessages, body)),
organizationId: Arg.Is<string>(orgId => eventMessage.OrganizationId.ToString().Equals(orgId)));
}
private static bool AssertJsonStringsMatch(EventMessage expected, string body)

View File

@@ -23,6 +23,7 @@ public class EventIntegrationHandlerTests
private const string _templateWithOrganization = "Org: #OrganizationName#";
private const string _templateWithUser = "#UserName#, #UserEmail#";
private const string _templateWithActingUser = "#ActingUserName#, #ActingUserEmail#";
private static readonly Guid _organizationId = Guid.NewGuid();
private static readonly Uri _uri = new Uri("https://localhost");
private static readonly Uri _uri2 = new Uri("https://example.com");
private readonly IEventIntegrationPublisher _eventIntegrationPublisher = Substitute.For<IEventIntegrationPublisher>();
@@ -50,6 +51,7 @@ public class EventIntegrationHandlerTests
{
IntegrationType = IntegrationType.Webhook,
MessageId = "TestMessageId",
OrganizationId = _organizationId.ToString(),
Configuration = new WebhookIntegrationConfigurationDetails(_uri),
RenderedTemplate = template,
RetryCount = 0,
@@ -122,6 +124,7 @@ public class EventIntegrationHandlerTests
public async Task HandleEventAsync_BaseTemplateOneConfiguration_PublishesIntegrationMessage(EventMessage eventMessage)
{
var sutProvider = GetSutProvider(OneConfiguration(_templateBase));
eventMessage.OrganizationId = _organizationId;
await sutProvider.Sut.HandleEventAsync(eventMessage);
@@ -140,6 +143,7 @@ public class EventIntegrationHandlerTests
public async Task HandleEventAsync_BaseTemplateTwoConfigurations_PublishesIntegrationMessages(EventMessage eventMessage)
{
var sutProvider = GetSutProvider(TwoConfigurations(_templateBase));
eventMessage.OrganizationId = _organizationId;
await sutProvider.Sut.HandleEventAsync(eventMessage);
@@ -164,6 +168,7 @@ public class EventIntegrationHandlerTests
var user = Substitute.For<User>();
user.Email = "test@example.com";
user.Name = "Test";
eventMessage.OrganizationId = _organizationId;
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(user);
await sutProvider.Sut.HandleEventAsync(eventMessage);
@@ -183,6 +188,7 @@ public class EventIntegrationHandlerTests
var sutProvider = GetSutProvider(OneConfiguration(_templateWithOrganization));
var organization = Substitute.For<Organization>();
organization.Name = "Test";
eventMessage.OrganizationId = _organizationId;
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(organization);
await sutProvider.Sut.HandleEventAsync(eventMessage);
@@ -205,6 +211,7 @@ public class EventIntegrationHandlerTests
var user = Substitute.For<User>();
user.Email = "test@example.com";
user.Name = "Test";
eventMessage.OrganizationId = _organizationId;
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(user);
await sutProvider.Sut.HandleEventAsync(eventMessage);
@@ -235,6 +242,7 @@ public class EventIntegrationHandlerTests
var sutProvider = GetSutProvider(ValidFilterConfiguration());
sutProvider.GetDependency<IIntegrationFilterService>().EvaluateFilterGroup(
Arg.Any<IntegrationFilterGroup>(), Arg.Any<EventMessage>()).Returns(true);
eventMessage.OrganizationId = _organizationId;
await sutProvider.Sut.HandleEventAsync(eventMessage);
@@ -284,7 +292,7 @@ public class EventIntegrationHandlerTests
$"Date: {eventMessage.Date}, Type: {eventMessage.Type}, UserId: {eventMessage.UserId}"
);
await _eventIntegrationPublisher.Received(1).PublishAsync(Arg.Is(
AssertHelper.AssertPropertyEqual(expectedMessage, new[] { "MessageId" })));
AssertHelper.AssertPropertyEqual(expectedMessage, new[] { "MessageId", "OrganizationId" })));
}
}
@@ -301,12 +309,12 @@ public class EventIntegrationHandlerTests
var expectedMessage = EventIntegrationHandlerTests.expectedMessage(
$"Date: {eventMessage.Date}, Type: {eventMessage.Type}, UserId: {eventMessage.UserId}"
);
await _eventIntegrationPublisher.Received(1).PublishAsync(Arg.Is(
AssertHelper.AssertPropertyEqual(expectedMessage, new[] { "MessageId" })));
await _eventIntegrationPublisher.Received(1).PublishAsync(Arg.Is(AssertHelper.AssertPropertyEqual(
expectedMessage, new[] { "MessageId", "OrganizationId" })));
expectedMessage.Configuration = new WebhookIntegrationConfigurationDetails(_uri2);
await _eventIntegrationPublisher.Received(1).PublishAsync(Arg.Is(
AssertHelper.AssertPropertyEqual(expectedMessage, new[] { "MessageId" })));
await _eventIntegrationPublisher.Received(1).PublishAsync(Arg.Is(AssertHelper.AssertPropertyEqual(
expectedMessage, new[] { "MessageId", "OrganizationId" })));
}
}
}

View File

@@ -16,6 +16,7 @@ public class IntegrationHandlerTests
{
Configuration = new WebhookIntegrationConfigurationDetails(new Uri("https://localhost"), "Bearer", "AUTH-TOKEN"),
MessageId = "TestMessageId",
OrganizationId = "TestOrganizationId",
IntegrationType = IntegrationType.Webhook,
RenderedTemplate = "Template",
DelayUntilDate = null,
@@ -25,6 +26,8 @@ public class IntegrationHandlerTests
var result = await sut.HandleAsync(expected.ToJson());
var typedResult = Assert.IsType<IntegrationMessage<WebhookIntegrationConfigurationDetails>>(result.Message);
Assert.Equal(expected.MessageId, typedResult.MessageId);
Assert.Equal(expected.OrganizationId, typedResult.OrganizationId);
Assert.Equal(expected.Configuration, typedResult.Configuration);
Assert.Equal(expected.RenderedTemplate, typedResult.RenderedTemplate);
Assert.Equal(expected.IntegrationType, typedResult.IntegrationType);

View File

@@ -113,6 +113,242 @@ public class CipherServiceTests
await sutProvider.GetDependency<ICipherRepository>().Received(1).ReplaceAsync(cipherDetails);
}
[Theory, BitAutoData]
public async Task CreateAttachmentAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider, Cipher cipher, Guid savingUserId)
{
var lastKnownRevisionDate = cipher.RevisionDate.AddDays(-1);
var stream = new MemoryStream();
var fileName = "test.txt";
var key = "test-key";
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.CreateAttachmentAsync(cipher, stream, fileName, key, 100, savingUserId, false, lastKnownRevisionDate));
Assert.Contains("out of date", exception.Message);
}
[Theory]
[BitAutoData("")]
[BitAutoData("Correct Time")]
public async Task CreateAttachmentAsync_CorrectRevisionDate_DoesNotThrow(string revisionDateString,
SutProvider<CipherService> sutProvider, CipherDetails cipher, Guid savingUserId)
{
var lastKnownRevisionDate = string.IsNullOrEmpty(revisionDateString) ? (DateTime?)null : cipher.RevisionDate;
var stream = new MemoryStream(new byte[100]);
var fileName = "test.txt";
var key = "test-key";
// Setup cipher with user ownership
cipher.UserId = savingUserId;
cipher.OrganizationId = null;
// Mock user storage and premium access
var user = new User { Id = savingUserId, MaxStorageGb = 1 };
sutProvider.GetDependency<IUserRepository>()
.GetByIdAsync(savingUserId)
.Returns(user);
sutProvider.GetDependency<IUserService>()
.CanAccessPremium(user)
.Returns(true);
sutProvider.GetDependency<IAttachmentStorageService>()
.UploadNewAttachmentAsync(Arg.Any<Stream>(), cipher, Arg.Any<CipherAttachment.MetaData>())
.Returns(Task.CompletedTask);
sutProvider.GetDependency<IAttachmentStorageService>()
.ValidateFileAsync(cipher, Arg.Any<CipherAttachment.MetaData>(), Arg.Any<long>())
.Returns((true, 100L));
sutProvider.GetDependency<ICipherRepository>()
.UpdateAttachmentAsync(Arg.Any<CipherAttachment>())
.Returns(Task.CompletedTask);
sutProvider.GetDependency<ICipherRepository>()
.ReplaceAsync(Arg.Any<CipherDetails>())
.Returns(Task.CompletedTask);
await sutProvider.Sut.CreateAttachmentAsync(cipher, stream, fileName, key, 100, savingUserId, false, lastKnownRevisionDate);
await sutProvider.GetDependency<IAttachmentStorageService>().Received(1)
.UploadNewAttachmentAsync(Arg.Any<Stream>(), cipher, Arg.Any<CipherAttachment.MetaData>());
}
[Theory, BitAutoData]
public async Task CreateAttachmentForDelayedUploadAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider, Cipher cipher, Guid savingUserId)
{
var lastKnownRevisionDate = cipher.RevisionDate.AddDays(-1);
var key = "test-key";
var fileName = "test.txt";
var fileSize = 100L;
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.CreateAttachmentForDelayedUploadAsync(cipher, key, fileName, fileSize, false, savingUserId, lastKnownRevisionDate));
Assert.Contains("out of date", exception.Message);
}
[Theory]
[BitAutoData("")]
[BitAutoData("Correct Time")]
public async Task CreateAttachmentForDelayedUploadAsync_CorrectRevisionDate_DoesNotThrow(string revisionDateString,
SutProvider<CipherService> sutProvider, CipherDetails cipher, Guid savingUserId)
{
var lastKnownRevisionDate = string.IsNullOrEmpty(revisionDateString) ? (DateTime?)null : cipher.RevisionDate;
var key = "test-key";
var fileName = "test.txt";
var fileSize = 100L;
// Setup cipher with user ownership
cipher.UserId = savingUserId;
cipher.OrganizationId = null;
// Mock user storage and premium access
var user = new User { Id = savingUserId, MaxStorageGb = 1 };
sutProvider.GetDependency<IUserRepository>()
.GetByIdAsync(savingUserId)
.Returns(user);
sutProvider.GetDependency<IUserService>()
.CanAccessPremium(user)
.Returns(true);
sutProvider.GetDependency<IAttachmentStorageService>()
.GetAttachmentUploadUrlAsync(cipher, Arg.Any<CipherAttachment.MetaData>())
.Returns("https://example.com/upload");
sutProvider.GetDependency<ICipherRepository>()
.UpdateAttachmentAsync(Arg.Any<CipherAttachment>())
.Returns(Task.CompletedTask);
var result = await sutProvider.Sut.CreateAttachmentForDelayedUploadAsync(cipher, key, fileName, fileSize, false, savingUserId, lastKnownRevisionDate);
Assert.NotNull(result.attachmentId);
Assert.NotNull(result.uploadUrl);
}
[Theory, BitAutoData]
public async Task UploadFileForExistingAttachmentAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider,
Cipher cipher)
{
var lastKnownRevisionDate = cipher.RevisionDate.AddDays(-1);
var stream = new MemoryStream();
var attachment = new CipherAttachment.MetaData
{
AttachmentId = "test-attachment-id",
Size = 100,
FileName = "test.txt",
Key = "test-key"
};
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.UploadFileForExistingAttachmentAsync(stream, cipher, attachment, lastKnownRevisionDate));
Assert.Contains("out of date", exception.Message);
}
[Theory]
[BitAutoData("")]
[BitAutoData("Correct Time")]
public async Task UploadFileForExistingAttachmentAsync_CorrectRevisionDate_DoesNotThrow(string revisionDateString,
SutProvider<CipherService> sutProvider, CipherDetails cipher)
{
var lastKnownRevisionDate = string.IsNullOrEmpty(revisionDateString) ? (DateTime?)null : cipher.RevisionDate;
var stream = new MemoryStream(new byte[100]);
var attachmentId = "test-attachment-id";
var attachment = new CipherAttachment.MetaData
{
AttachmentId = attachmentId,
Size = 100,
FileName = "test.txt",
Key = "test-key"
};
// Set the attachment on the cipher so ValidateCipherAttachmentFile can find it
cipher.SetAttachments(new Dictionary<string, CipherAttachment.MetaData>
{
[attachmentId] = attachment
});
sutProvider.GetDependency<IAttachmentStorageService>()
.UploadNewAttachmentAsync(stream, cipher, attachment)
.Returns(Task.CompletedTask);
sutProvider.GetDependency<IAttachmentStorageService>()
.ValidateFileAsync(cipher, attachment, Arg.Any<long>())
.Returns((true, 100L));
sutProvider.GetDependency<ICipherRepository>()
.UpdateAttachmentAsync(Arg.Any<CipherAttachment>())
.Returns(Task.CompletedTask);
await sutProvider.Sut.UploadFileForExistingAttachmentAsync(stream, cipher, attachment, lastKnownRevisionDate);
await sutProvider.GetDependency<IAttachmentStorageService>().Received(1)
.UploadNewAttachmentAsync(stream, cipher, attachment);
}
[Theory, BitAutoData]
public async Task CreateAttachmentShareAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider,
Cipher cipher, Guid organizationId)
{
var lastKnownRevisionDate = cipher.RevisionDate.AddDays(-1);
var stream = new MemoryStream();
var fileName = "test.txt";
var key = "test-key";
var attachmentId = "attachment-id";
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.CreateAttachmentShareAsync(cipher, stream, fileName, key, 100, attachmentId, organizationId, lastKnownRevisionDate));
Assert.Contains("out of date", exception.Message);
}
[Theory]
[BitAutoData("")]
[BitAutoData("Correct Time")]
public async Task CreateAttachmentShareAsync_CorrectRevisionDate_DoesNotThrow(string revisionDateString,
SutProvider<CipherService> sutProvider, CipherDetails cipher, Guid organizationId)
{
var lastKnownRevisionDate = string.IsNullOrEmpty(revisionDateString) ? (DateTime?)null : cipher.RevisionDate;
var stream = new MemoryStream(new byte[100]);
var fileName = "test.txt";
var key = "test-key";
var attachmentId = "attachment-id";
// Setup cipher with existing attachment (no TempMetadata)
cipher.OrganizationId = null;
cipher.SetAttachments(new Dictionary<string, CipherAttachment.MetaData>
{
[attachmentId] = new CipherAttachment.MetaData
{
AttachmentId = attachmentId,
Size = 100,
FileName = "existing.txt",
Key = "existing-key"
}
});
// Mock organization
var organization = new Organization
{
Id = organizationId,
MaxStorageGb = 1
};
sutProvider.GetDependency<IOrganizationRepository>()
.GetByIdAsync(organizationId)
.Returns(organization);
sutProvider.GetDependency<IAttachmentStorageService>()
.UploadShareAttachmentAsync(stream, cipher.Id, organizationId, Arg.Any<CipherAttachment.MetaData>())
.Returns(Task.CompletedTask);
sutProvider.GetDependency<ICipherRepository>()
.UpdateAttachmentAsync(Arg.Any<CipherAttachment>())
.Returns(Task.CompletedTask);
await sutProvider.Sut.CreateAttachmentShareAsync(cipher, stream, fileName, key, 100, attachmentId, organizationId, lastKnownRevisionDate);
await sutProvider.GetDependency<IAttachmentStorageService>().Received(1)
.UploadShareAttachmentAsync(stream, cipher.Id, organizationId, Arg.Any<CipherAttachment.MetaData>());
}
[Theory]
[BitAutoData]
public async Task SaveDetailsAsync_PersonalVault_WithOrganizationDataOwnershipPolicyEnabled_Throws(

View File

@@ -0,0 +1,250 @@
#nullable enable
using System.Text.Json;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Test.NotificationCenter.AutoFixture;
using Bit.Core.Utilities;
using Bit.Notifications;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.AspNetCore.SignalR;
using NSubstitute;
namespace Notifications.Test;
[SutProviderCustomize]
[NotificationCustomize(false)]
public class HubHelpersTest
{
[Theory]
[BitAutoData]
public async Task SendNotificationToHubAsync_NotificationPushNotificationGlobal_NothingSent(
SutProvider<HubHelpers> sutProvider,
NotificationPushNotification notification,
string contextId, CancellationToken cancellationToke)
{
notification.Global = true;
notification.InstallationId = null;
notification.UserId = null;
notification.OrganizationId = null;
var json = ToNotificationJson(notification, PushType.Notification, contextId);
await sutProvider.Sut.SendNotificationToHubAsync(json, cancellationToke);
sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(0).User(Arg.Any<string>());
sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(0).Group(Arg.Any<string>());
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0).User(Arg.Any<string>());
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0)
.Group(Arg.Any<string>());
}
[Theory]
[BitAutoData]
public async Task
SendNotificationToHubAsync_NotificationPushNotificationInstallationIdProvidedClientTypeAll_SentToGroupInstallation(
SutProvider<HubHelpers> sutProvider,
NotificationPushNotification notification,
string contextId, CancellationToken cancellationToken)
{
notification.UserId = null;
notification.OrganizationId = null;
notification.ClientType = ClientType.All;
var json = ToNotificationJson(notification, PushType.Notification, contextId);
await sutProvider.Sut.SendNotificationToHubAsync(json, cancellationToken);
sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(0).User(Arg.Any<string>());
await sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(1)
.Group($"Installation_{notification.InstallationId!.Value.ToString()}")
.Received(1)
.SendCoreAsync("ReceiveMessage", Arg.Is<object?[]>(objects =>
objects.Length == 1 && IsNotificationPushNotificationEqual(notification, objects[0],
PushType.Notification, contextId)),
cancellationToken);
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0).User(Arg.Any<string>());
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0)
.Group(Arg.Any<string>());
}
[Theory]
[BitAutoData(ClientType.Browser)]
[BitAutoData(ClientType.Desktop)]
[BitAutoData(ClientType.Mobile)]
[BitAutoData(ClientType.Web)]
public async Task
SendNotificationToHubAsync_NotificationPushNotificationInstallationIdProvidedClientTypeNotAll_SentToGroupInstallationClientType(
ClientType clientType, SutProvider<HubHelpers> sutProvider,
NotificationPushNotification notification,
string contextId, CancellationToken cancellationToken)
{
notification.UserId = null;
notification.OrganizationId = null;
notification.ClientType = clientType;
var json = ToNotificationJson(notification, PushType.Notification, contextId);
await sutProvider.Sut.SendNotificationToHubAsync(json, cancellationToken);
sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(0).User(Arg.Any<string>());
await sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(1)
.Group($"Installation_ClientType_{notification.InstallationId!.Value}_{clientType}")
.Received(1)
.SendCoreAsync("ReceiveMessage", Arg.Is<object?[]>(objects =>
objects.Length == 1 && IsNotificationPushNotificationEqual(notification, objects[0],
PushType.Notification, contextId)),
cancellationToken);
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0).User(Arg.Any<string>());
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0)
.Group(Arg.Any<string>());
}
[Theory]
[BitAutoData(false)]
[BitAutoData(true)]
public async Task SendNotificationToHubAsync_NotificationPushNotificationUserIdProvidedClientTypeAll_SentToUser(
bool organizationIdProvided, SutProvider<HubHelpers> sutProvider,
NotificationPushNotification notification,
string contextId, CancellationToken cancellationToken)
{
notification.InstallationId = null;
notification.ClientType = ClientType.All;
if (!organizationIdProvided)
{
notification.OrganizationId = null;
}
var json = ToNotificationJson(notification, PushType.Notification, contextId);
await sutProvider.Sut.SendNotificationToHubAsync(json, cancellationToken);
await sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(1)
.User(notification.UserId!.Value.ToString())
.Received(1)
.SendCoreAsync("ReceiveMessage", Arg.Is<object?[]>(objects =>
objects.Length == 1 && IsNotificationPushNotificationEqual(notification, objects[0],
PushType.Notification, contextId)),
cancellationToken);
sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(0).Group(Arg.Any<string>());
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0).User(Arg.Any<string>());
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0)
.Group(Arg.Any<string>());
}
[Theory]
[BitAutoData(false, ClientType.Browser)]
[BitAutoData(false, ClientType.Desktop)]
[BitAutoData(false, ClientType.Mobile)]
[BitAutoData(false, ClientType.Web)]
[BitAutoData(true, ClientType.Browser)]
[BitAutoData(true, ClientType.Desktop)]
[BitAutoData(true, ClientType.Mobile)]
[BitAutoData(true, ClientType.Web)]
public async Task
SendNotificationToHubAsync_NotificationPushNotificationUserIdProvidedClientTypeNotAll_SentToGroupUserClientType(
bool organizationIdProvided, ClientType clientType, SutProvider<HubHelpers> sutProvider,
NotificationPushNotification notification,
string contextId, CancellationToken cancellationToken)
{
notification.InstallationId = null;
notification.ClientType = clientType;
if (!organizationIdProvided)
{
notification.OrganizationId = null;
}
var json = ToNotificationJson(notification, PushType.Notification, contextId);
await sutProvider.Sut.SendNotificationToHubAsync(json, cancellationToken);
sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(0).User(Arg.Any<string>());
await sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(1)
.Group($"UserClientType_{notification.UserId!.Value}_{clientType}")
.Received(1)
.SendCoreAsync("ReceiveMessage", Arg.Is<object?[]>(objects =>
objects.Length == 1 && IsNotificationPushNotificationEqual(notification, objects[0],
PushType.Notification, contextId)),
cancellationToken);
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0).User(Arg.Any<string>());
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0)
.Group(Arg.Any<string>());
}
[Theory]
[BitAutoData]
public async Task
SendNotificationToHubAsync_NotificationPushNotificationOrganizationIdProvidedClientTypeAll_SentToGroupOrganization(
SutProvider<HubHelpers> sutProvider, string contextId,
NotificationPushNotification notification,
CancellationToken cancellationToken)
{
notification.UserId = null;
notification.InstallationId = null;
notification.ClientType = ClientType.All;
var json = ToNotificationJson(notification, PushType.Notification, contextId);
await sutProvider.Sut.SendNotificationToHubAsync(json, cancellationToken);
sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(0).User(Arg.Any<string>());
await sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(1)
.Group($"Organization_{notification.OrganizationId!.Value}")
.Received(1)
.SendCoreAsync("ReceiveMessage", Arg.Is<object?[]>(objects =>
objects.Length == 1 && IsNotificationPushNotificationEqual(notification, objects[0],
PushType.Notification, contextId)),
cancellationToken);
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0).User(Arg.Any<string>());
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0)
.Group(Arg.Any<string>());
}
[Theory]
[BitAutoData(ClientType.Browser)]
[BitAutoData(ClientType.Desktop)]
[BitAutoData(ClientType.Mobile)]
[BitAutoData(ClientType.Web)]
public async Task
SendNotificationToHubAsync_NotificationPushNotificationOrganizationIdProvidedClientTypeNotAll_SentToGroupOrganizationClientType(
ClientType clientType, SutProvider<HubHelpers> sutProvider, string contextId,
NotificationPushNotification notification,
CancellationToken cancellationToken)
{
notification.UserId = null;
notification.InstallationId = null;
notification.ClientType = clientType;
var json = ToNotificationJson(notification, PushType.Notification, contextId);
await sutProvider.Sut.SendNotificationToHubAsync(json, cancellationToken);
sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(0).User(Arg.Any<string>());
await sutProvider.GetDependency<IHubContext<NotificationsHub>>().Clients.Received(1)
.Group($"OrganizationClientType_{notification.OrganizationId!.Value}_{clientType}")
.Received(1)
.SendCoreAsync("ReceiveMessage", Arg.Is<object?[]>(objects =>
objects.Length == 1 && IsNotificationPushNotificationEqual(notification, objects[0],
PushType.Notification, contextId)),
cancellationToken);
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0).User(Arg.Any<string>());
sutProvider.GetDependency<IHubContext<AnonymousNotificationsHub>>().Clients.Received(0)
.Group(Arg.Any<string>());
}
private static string ToNotificationJson(object payload, PushType type, string contextId)
{
var notification = new PushNotificationData<object>(type, payload, contextId);
return JsonSerializer.Serialize(notification, JsonHelpers.IgnoreWritingNull);
}
private static bool IsNotificationPushNotificationEqual(NotificationPushNotification expected, object? actual,
PushType type, string contextId)
{
if (actual is not PushNotificationData<NotificationPushNotification> pushNotificationData)
{
return false;
}
return pushNotificationData.Type == type &&
pushNotificationData.ContextId == contextId &&
expected.Id == pushNotificationData.Payload.Id &&
expected.UserId == pushNotificationData.Payload.UserId &&
expected.OrganizationId == pushNotificationData.Payload.OrganizationId &&
expected.ClientType == pushNotificationData.Payload.ClientType &&
expected.RevisionDate == pushNotificationData.Payload.RevisionDate;
}
}

View File

@@ -18,5 +18,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Notifications\Notifications.csproj" />
<ProjectReference Include="..\Common\Common.csproj" />
<ProjectReference Include="..\Core.Test\Core.Test.csproj" />
</ItemGroup>
</Project>