1
0
mirror of https://github.com/bitwarden/server.git synced 2025-02-20 02:31:30 +01:00

PM-10563: Unit Tests

This commit is contained in:
Maciej Zieniuk 2024-10-04 14:03:08 +01:00
parent 0ee4bc11a0
commit aa7a62d586
No known key found for this signature in database
GPG Key ID: 9CACE59F1272ACD9
3 changed files with 215 additions and 64 deletions

View File

@ -1,10 +1,13 @@
#nullable enable
using System.Text.Json;
using Bit.Api.NotificationCenter.Controllers;
using Bit.Api.NotificationCenter.Models.Request;
using Bit.Core.NotificationCenter.Entities;
using Bit.Core.NotificationCenter.Commands.Interfaces;
using Bit.Core.NotificationCenter.Models.Data;
using Bit.Core.NotificationCenter.Models.Filter;
using Bit.Core.NotificationCenter.Queries.Interfaces;
using Bit.Core.Test.NotificationCenter.AutoFixture;
using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
@ -17,36 +20,188 @@ namespace Bit.Api.Test.NotificationCenter.Controllers;
public class NotificationsControllerTest
{
[Theory]
[BitAutoData]
[NotificationListCustomize(20)]
public async Task List_DefaultFilter_ReturnedMatchingNotifications(SutProvider<NotificationsController> sutProvider,
List<Notification> notifications)
[BitAutoData([null, null])]
[BitAutoData([null, false])]
[BitAutoData([null, true])]
[BitAutoData(false, null)]
[BitAutoData(true, null)]
[BitAutoData(false, false)]
[BitAutoData(false, true)]
[BitAutoData(true, false)]
[BitAutoData(true, true)]
[NotificationStatusDetailsListCustomize(5)]
public async Task List_StatusFilter_ReturnedMatchingNotifications(bool? readStatusFilter, bool? deletedStatusFilter,
SutProvider<NotificationsController> sutProvider,
IEnumerable<NotificationStatusDetails> notificationStatusDetailsEnumerable)
{
sutProvider.GetDependency<IGetNotificationsForUserQuery>()
.GetByUserIdStatusFilterAsync(Arg.Any<NotificationStatusFilter>())
.Returns(notifications);
var notificationStatusDetailsList = notificationStatusDetailsEnumerable
.OrderByDescending(n => n.Priority)
.ThenByDescending(n => n.CreationDate)
.ToList();
var expectedNotificationGroupedById = notifications
sutProvider.GetDependency<IGetNotificationStatusDetailsForUserQuery>()
.GetByUserIdStatusFilterAsync(Arg.Any<NotificationStatusFilter>())
.Returns(notificationStatusDetailsList);
var expectedNotificationStatusDetailsMap = notificationStatusDetailsList
.Take(10)
.ToDictionary(n => n.Id);
var filter = new NotificationFilterRequestModel();
var listResponse = await sutProvider.Sut.List(new NotificationFilterRequestModel
{
ReadStatusFilter = readStatusFilter,
DeletedStatusFilter = deletedStatusFilter
});
var listResponse = await sutProvider.Sut.List(filter);
Assert.Equal("list", listResponse.Object);
Assert.Equal(5, listResponse.Data.Count());
Assert.All(listResponse.Data, notificationResponseModel =>
{
Assert.Equal("notification", notificationResponseModel.Object);
Assert.True(expectedNotificationStatusDetailsMap.ContainsKey(notificationResponseModel.Id));
var expectedNotificationStatusDetails = expectedNotificationStatusDetailsMap[notificationResponseModel.Id];
Assert.NotNull(expectedNotificationStatusDetails);
Assert.Equal(expectedNotificationStatusDetails.Id, notificationResponseModel.Id);
Assert.Equal(expectedNotificationStatusDetails.Priority, notificationResponseModel.Priority);
Assert.Equal(expectedNotificationStatusDetails.Title, notificationResponseModel.Title);
Assert.Equal(expectedNotificationStatusDetails.Body, notificationResponseModel.Body);
Assert.Equal(expectedNotificationStatusDetails.RevisionDate, notificationResponseModel.Date);
Assert.Equal(expectedNotificationStatusDetails.ReadDate, notificationResponseModel.ReadDate);
Assert.Equal(expectedNotificationStatusDetails.DeletedDate, notificationResponseModel.DeletedDate);
});
Assert.Null(listResponse.ContinuationToken);
await sutProvider.GetDependency<IGetNotificationStatusDetailsForUserQuery>()
.Received(1)
.GetByUserIdStatusFilterAsync(Arg.Is<NotificationStatusFilter>(filter =>
filter.Read == readStatusFilter && filter.Deleted == deletedStatusFilter));
}
[Theory]
[BitAutoData]
[NotificationStatusDetailsListCustomize(19)]
public async Task List_PagingNoContinuationToken_ReturnedFirst10MatchingNotifications(
SutProvider<NotificationsController> sutProvider,
IEnumerable<NotificationStatusDetails> notificationStatusDetailsEnumerable)
{
var notificationStatusDetailsList = notificationStatusDetailsEnumerable
.OrderByDescending(n => n.Priority)
.ThenByDescending(n => n.CreationDate)
.ToList();
sutProvider.GetDependency<IGetNotificationStatusDetailsForUserQuery>()
.GetByUserIdStatusFilterAsync(Arg.Any<NotificationStatusFilter>())
.Returns(notificationStatusDetailsList);
var expectedNotificationStatusDetailsMap = notificationStatusDetailsList
.Take(10)
.ToDictionary(n => n.Id);
var listResponse = await sutProvider.Sut.List(new NotificationFilterRequestModel());
Assert.Equal("list", listResponse.Object);
Assert.Equal(10, listResponse.Data.Count());
Assert.All(listResponse.Data, notificationResponseModel =>
{
var expectedNotification = expectedNotificationGroupedById[notificationResponseModel.Id];
Assert.NotNull(expectedNotification);
Assert.Equal(expectedNotification.Id, notificationResponseModel.Id);
Assert.Equal(expectedNotification.Priority, notificationResponseModel.Priority);
Assert.Equal(expectedNotification.Title, notificationResponseModel.Title);
Assert.Equal(expectedNotification.Body, notificationResponseModel.Body);
Assert.Equal(expectedNotification.RevisionDate, notificationResponseModel.Date);
Assert.Equal("notification", notificationResponseModel.Object);
Assert.True(expectedNotificationStatusDetailsMap.ContainsKey(notificationResponseModel.Id));
var expectedNotificationStatusDetails = expectedNotificationStatusDetailsMap[notificationResponseModel.Id];
Assert.NotNull(expectedNotificationStatusDetails);
Assert.Equal(expectedNotificationStatusDetails.Id, notificationResponseModel.Id);
Assert.Equal(expectedNotificationStatusDetails.Priority, notificationResponseModel.Priority);
Assert.Equal(expectedNotificationStatusDetails.Title, notificationResponseModel.Title);
Assert.Equal(expectedNotificationStatusDetails.Body, notificationResponseModel.Body);
Assert.Equal(expectedNotificationStatusDetails.RevisionDate, notificationResponseModel.Date);
Assert.Equal(expectedNotificationStatusDetails.ReadDate, notificationResponseModel.ReadDate);
Assert.Equal(expectedNotificationStatusDetails.DeletedDate, notificationResponseModel.DeletedDate);
});
var expectedContinuationToken = new Dictionary<string, object>
{
{ "priority", notificationStatusDetailsList[9].Priority },
{ "date", notificationStatusDetailsList[9].CreationDate }
};
var expectedJsonContinuationToken = JsonSerializer.Serialize(expectedContinuationToken);
var expectedBase64EncodedJsonContinuationToken =
CoreHelpers.Base64UrlEncodeString(expectedJsonContinuationToken);
Assert.Equal(expectedBase64EncodedJsonContinuationToken, listResponse.ContinuationToken);
}
[Theory]
[BitAutoData]
[NotificationStatusDetailsListCustomize(19)]
public async Task List_PagingUsingContinuationToken_ReturnedLast9MatchingNotifications(
SutProvider<NotificationsController> sutProvider,
IEnumerable<NotificationStatusDetails> notificationStatusDetailsEnumerable)
{
var notificationStatusDetailsList = notificationStatusDetailsEnumerable
.OrderByDescending(n => n.Priority)
.ThenByDescending(n => n.CreationDate)
.ToList();
sutProvider.GetDependency<IGetNotificationStatusDetailsForUserQuery>()
.GetByUserIdStatusFilterAsync(Arg.Any<NotificationStatusFilter>())
.Returns(notificationStatusDetailsList);
var expectedNotificationStatusDetailsMap = notificationStatusDetailsList
.Skip(10)
.ToDictionary(n => n.Id);
var continuationToken = new Dictionary<string, object>
{
{ "priority", notificationStatusDetailsList[9].Priority },
{ "date", notificationStatusDetailsList[9].CreationDate }
};
var jsonContinuationToken = JsonSerializer.Serialize(continuationToken);
var base64EncodedJsonContinuationToken = CoreHelpers.Base64UrlEncodeString(jsonContinuationToken);
var listResponse = await sutProvider.Sut.List(new NotificationFilterRequestModel
{
ContinuationToken = base64EncodedJsonContinuationToken
});
Assert.Equal("list", listResponse.Object);
Assert.Equal(9, listResponse.Data.Count());
Assert.All(listResponse.Data, notificationResponseModel =>
{
Assert.Equal("notification", notificationResponseModel.Object);
Assert.True(expectedNotificationStatusDetailsMap.ContainsKey(notificationResponseModel.Id));
var expectedNotificationStatusDetails = expectedNotificationStatusDetailsMap[notificationResponseModel.Id];
Assert.NotNull(expectedNotificationStatusDetails);
Assert.Equal(expectedNotificationStatusDetails.Id, notificationResponseModel.Id);
Assert.Equal(expectedNotificationStatusDetails.Priority, notificationResponseModel.Priority);
Assert.Equal(expectedNotificationStatusDetails.Title, notificationResponseModel.Title);
Assert.Equal(expectedNotificationStatusDetails.Body, notificationResponseModel.Body);
Assert.Equal(expectedNotificationStatusDetails.RevisionDate, notificationResponseModel.Date);
Assert.Equal(expectedNotificationStatusDetails.ReadDate, notificationResponseModel.ReadDate);
Assert.Equal(expectedNotificationStatusDetails.DeletedDate, notificationResponseModel.DeletedDate);
});
Assert.Null(listResponse.ContinuationToken);
Assert.Equal("list", listResponse.Object);
}
[Theory]
[BitAutoData]
public async Task MarkAsDeleted_NotificationId_MarkedAsDeleted(
SutProvider<NotificationsController> sutProvider,
Guid notificationId)
{
await sutProvider.Sut.MarkAsDeleted(notificationId);
await sutProvider.GetDependency<IMarkNotificationDeletedCommand>()
.Received(1)
.MarkDeletedAsync(notificationId);
}
[Theory]
[BitAutoData]
public async Task MarkAsRead_NotificationId_MarkedAsRead(
SutProvider<NotificationsController> sutProvider,
Guid notificationId)
{
await sutProvider.Sut.MarkAsRead(notificationId);
await sutProvider.GetDependency<IMarkNotificationReadCommand>()
.Received(1)
.MarkReadAsync(notificationId);
}
}

View File

@ -1,7 +1,5 @@
#nullable enable
using AutoFixture;
using AutoFixture.Dsl;
using AutoFixture.Kernel;
using Bit.Core.NotificationCenter.Entities;
using Bit.Test.Common.AutoFixture.Attributes;
@ -11,44 +9,19 @@ public class NotificationCustomization(bool global) : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<Notification>(GetSpecimenBuilder);
}
public ISpecimenBuilder GetSpecimenBuilder(ICustomizationComposer<Notification> customizationComposer)
{
var postprocessComposer = customizationComposer.With(n => n.Id, Guid.NewGuid())
.With(n => n.Global, global);
postprocessComposer = global
? postprocessComposer.Without(n => n.UserId)
: postprocessComposer.With(n => n.UserId, Guid.NewGuid());
return global
? postprocessComposer.Without(n => n.OrganizationId)
: postprocessComposer.With(n => n.OrganizationId, Guid.NewGuid());
}
}
public class NotificationListCustomization(int count) : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<List<Notification>>(composer => composer.FromFactory(() =>
fixture.Customize<Notification>(composer =>
{
var notificationCustomization = new NotificationCustomization(true);
var postprocessComposer = composer.With(n => n.Id, Guid.NewGuid())
.With(n => n.Global, global);
var notifications = new List<Notification>();
for (var i = 0; i < count; i++)
{
var customizationComposer = fixture.Build<Notification>();
var postprocessComposer =
customizationComposer.FromFactory(
notificationCustomization.GetSpecimenBuilder(customizationComposer));
notifications.Add(postprocessComposer.Create());
}
postprocessComposer = global
? postprocessComposer.Without(n => n.UserId)
: postprocessComposer.With(n => n.UserId, Guid.NewGuid());
return notifications;
}));
return global
? postprocessComposer.Without(n => n.OrganizationId)
: postprocessComposer.With(n => n.OrganizationId, Guid.NewGuid());
});
}
}
@ -56,8 +29,3 @@ public class NotificationCustomizeAttribute(bool global = true) : BitCustomizeAt
{
public override ICustomization GetCustomization() => new NotificationCustomization(global);
}
public class NotificationListCustomizeAttribute(int count) : BitCustomizeAttribute
{
public override ICustomization GetCustomization() => new NotificationListCustomization(count);
}

View File

@ -9,9 +9,32 @@ public class NotificationStatusDetailsCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<NotificationStatusDetails>(composer => composer.With(n => n.Id, Guid.NewGuid())
.With(n => n.UserId, Guid.NewGuid())
.With(n => n.OrganizationId, Guid.NewGuid()));
fixture.Customize<NotificationStatusDetails>(composer =>
{
return composer.With(n => n.Id, Guid.NewGuid())
.With(n => n.UserId, Guid.NewGuid())
.With(n => n.OrganizationId, Guid.NewGuid());
});
}
}
public class NotificationStatusDetailsListCustomization(int count) : ICustomization
{
public void Customize(IFixture fixture)
{
var customization = new NotificationStatusDetailsCustomization();
fixture.Customize<IEnumerable<NotificationStatusDetails>>(composer => composer.FromFactory(() =>
{
var notifications = new List<NotificationStatusDetails>();
for (var i = 0; i < count; i++)
{
customization.Customize(fixture);
var notificationStatusDetails = fixture.Create<NotificationStatusDetails>();
notifications.Add(notificationStatusDetails);
}
return notifications;
}));
}
}
@ -19,3 +42,8 @@ public class NotificationStatusDetailsCustomizeAttribute : BitCustomizeAttribute
{
public override ICustomization GetCustomization() => new NotificationStatusDetailsCustomization();
}
public class NotificationStatusDetailsListCustomizeAttribute(int count) : BitCustomizeAttribute
{
public override ICustomization GetCustomization() => new NotificationStatusDetailsListCustomization(count);
}