1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-05 21:18:13 -05:00

Re-write CollectionService unit tests with AutoFixtures (#1330)

* Add CollectionService unit tests

* Add missing CollectionFixtures

* Resolve pr comments

* Resolve PR comments
This commit is contained in:
Sang 2021-06-02 01:13:08 +10:00 committed by GitHub
parent 52dea4c2a4
commit 4f3d1587e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 151 additions and 144 deletions

View File

@ -0,0 +1,12 @@
using Bit.Core.Test.AutoFixture.Attributes;
using Bit.Core.Test.AutoFixture.OrganizationFixtures;
namespace Bit.Core.Test.AutoFixture
{
internal class CollectionAutoDataAttribute : CustomAutoDataAttribute
{
public CollectionAutoDataAttribute() : base(new SutProviderCustomization(), new Organization())
{ }
}
}

View File

@ -19,11 +19,17 @@ namespace Bit.Core.Test.AutoFixture.OrganizationFixtures
public void Customize(IFixture fixture) public void Customize(IFixture fixture)
{ {
var organizationId = Guid.NewGuid(); var organizationId = Guid.NewGuid();
var maxConnections = (short)new Random().Next(10, short.MaxValue);
fixture.Customize<Core.Models.Table.Organization>(composer => composer fixture.Customize<Core.Models.Table.Organization>(composer => composer
.With(o => o.Id, organizationId) .With(o => o.Id, organizationId)
.With(o => o.MaxCollections, maxConnections)
.With(o => o.UseGroups, UseGroups)); .With(o => o.UseGroups, UseGroups));
fixture.Customize<Core.Models.Table.Collection>(composer =>
composer
.With(c => c.OrganizationId, organizationId));
fixture.Customize<Group>(composer => composer.With(g => g.OrganizationId, organizationId)); fixture.Customize<Group>(composer => composer.With(g => g.OrganizationId, organizationId));
} }
} }
@ -53,7 +59,7 @@ namespace Bit.Core.Test.AutoFixture.OrganizationFixtures
var plansToIgnore = new List<PlanType> { PlanType.Free, PlanType.Custom }; var plansToIgnore = new List<PlanType> { PlanType.Free, PlanType.Custom };
var selectedPlan = StaticStore.Plans.Last(p => !plansToIgnore.Contains(p.Type) && !p.Disabled); var selectedPlan = StaticStore.Plans.Last(p => !plansToIgnore.Contains(p.Type) && !p.Disabled);
fixture.Customize<OrganizationUpgrade>(composer => composer fixture.Customize<OrganizationUpgrade>(composer => composer
.With(ou => ou.Plan, selectedPlan.Type) .With(ou => ou.Plan, selectedPlan.Type)
.With(ou => ou.PremiumAccessAddon, selectedPlan.HasPremiumAccessOption)); .With(ou => ou.PremiumAccessAddon, selectedPlan.HasPremiumAccessOption));

View File

@ -1,184 +1,173 @@
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xunit; using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Test.AutoFixture;
using Bit.Core.Test.AutoFixture.Attributes;
using NSubstitute; using NSubstitute;
using Bit.Core.Exceptions; using Xunit;
namespace Bit.Core.Test.Services namespace Bit.Core.Test.Services
{ {
public class CollectionServiceTest public class CollectionServiceTest
{ {
private readonly IEventService _eventService; [Theory, CollectionAutoData]
private readonly IOrganizationRepository _organizationRepository; public async Task SaveAsync_DefaultId_CreatesCollectionInTheRepository(Collection collection, Organization organization, SutProvider<CollectionService> sutProvider)
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly ICollectionRepository _collectionRepository;
private readonly IUserRepository _userRepository;
private readonly IMailService _mailService;
public CollectionServiceTest()
{ {
_eventService = Substitute.For<IEventService>(); collection.Id = default;
_organizationRepository = Substitute.For<IOrganizationRepository>(); sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
_organizationUserRepository = Substitute.For<IOrganizationUserRepository>(); var utcNow = DateTime.UtcNow;
_collectionRepository = Substitute.For<ICollectionRepository>();
_userRepository = Substitute.For<IUserRepository>(); await sutProvider.Sut.SaveAsync(collection);
_mailService = Substitute.For<IMailService>();
await sutProvider.GetDependency<ICollectionRepository>().Received().CreateAsync(collection);
await sutProvider.GetDependency<IEventService>().Received()
.LogCollectionEventAsync(collection, EventType.Collection_Created);
Assert.True(collection.CreationDate - utcNow < TimeSpan.FromSeconds(1));
Assert.True(collection.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
} }
[Fact] [Theory, CollectionAutoData]
public async Task SaveAsync_CollectionNotFound() public async Task SaveAsync_DefaultIdWithGroups_CreateCollectionWithGroupsInRepository(Collection collection,
IEnumerable<SelectionReadOnly> groups, Organization organization, OrganizationUser organizationUser,
SutProvider<CollectionService> sutProvider)
{ {
var collectionService = new CollectionService( collection.Id = default;
_eventService, organization.UseGroups = true;
_organizationRepository, sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
_organizationUserRepository, var utcNow = DateTime.UtcNow;
_collectionRepository,
_userRepository,
_mailService);
var id = Guid.NewGuid(); await sutProvider.Sut.SaveAsync(collection, groups);
var collection = new Core.Models.Table.Collection await sutProvider.GetDependency<ICollectionRepository>().Received().CreateAsync(collection, groups);
{ await sutProvider.GetDependency<IEventService>().Received()
Id = id, .LogCollectionEventAsync(collection, EventType.Collection_Created);
}; Assert.True(collection.CreationDate - utcNow < TimeSpan.FromSeconds(1));
Assert.True(collection.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
var ex = await Assert.ThrowsAsync<BadRequestException>(() => collectionService.SaveAsync(collection));
Assert.Equal("Organization not found", ex.Message);
} }
[Fact] [Theory, CollectionAutoData]
public async Task SaveAsync_DefaultCollectionId_CreatesCollectionInTheRepository() public async Task SaveAsync_NonDefaultId_ReplacesCollectionInRepository(Collection collection, Organization organization, SutProvider<CollectionService> sutProvider)
{ {
// prepare the organization var creationDate = collection.CreationDate;
var testOrganizationId = Guid.NewGuid(); sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
var testOrganization = new Core.Models.Table.Organization var utcNow = DateTime.UtcNow;
{
Id = testOrganizationId,
};
_organizationRepository.GetByIdAsync(testOrganizationId).Returns(testOrganization);
var collectionService = new CollectionService( await sutProvider.Sut.SaveAsync(collection);
_eventService,
_organizationRepository,
_organizationUserRepository,
_collectionRepository,
_userRepository,
_mailService);
// execute await sutProvider.GetDependency<ICollectionRepository>().Received().ReplaceAsync(collection);
var testCollection = new Core.Models.Table.Collection await sutProvider.GetDependency<IEventService>().Received()
{ .LogCollectionEventAsync(collection, EventType.Collection_Updated);
OrganizationId = testOrganizationId, Assert.Equal(collection.CreationDate, creationDate);
}; Assert.True(collection.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
await collectionService.SaveAsync(testCollection);
// verify
await _collectionRepository.Received().CreateAsync(testCollection);
} }
[Fact] [Theory, CollectionAutoData]
public async Task SaveAsync_RespectsMaxNumberOfCollectionsPerOrganization() public async Task SaveAsync_OrganizationNotUseGroup_CreateCollectionWithoutGroupsInRepository(Collection collection, IEnumerable<SelectionReadOnly> groups,
Organization organization, OrganizationUser organizationUser, SutProvider<CollectionService> sutProvider)
{ {
// prepare the organization collection.Id = default;
var testOrganizationId = Guid.NewGuid(); sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
var testOrganization = new Core.Models.Table.Organization var utcNow = DateTime.UtcNow;
{
Id = testOrganizationId,
MaxCollections = 2,
};
_organizationRepository.GetByIdAsync(testOrganizationId).Returns(testOrganization);
_collectionRepository.GetCountByOrganizationIdAsync(testOrganizationId).Returns(2);
// execute await sutProvider.Sut.SaveAsync(collection, groups);
var collectionService = new CollectionService(
_eventService,
_organizationRepository,
_organizationUserRepository,
_collectionRepository,
_userRepository,
_mailService);
var testCollection = new Core.Models.Table.Collection { OrganizationId = testOrganizationId }; await sutProvider.GetDependency<ICollectionRepository>().Received().CreateAsync(collection);
await sutProvider.GetDependency<IEventService>().Received()
// verify & expect exception to be thrown .LogCollectionEventAsync(collection, EventType.Collection_Created);
var ex = await Assert.ThrowsAsync<BadRequestException>(() => collectionService.SaveAsync(testCollection)); Assert.True(collection.CreationDate - utcNow < TimeSpan.FromSeconds(1));
Assert.True(collection.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
Assert.Equal("You have reached the maximum number of collections (2) for this organization.",
ex.Message);
} }
[Fact] [Theory, CollectionAutoData]
public async Task DeleteUserAsync_DeletesValidUserWhoBelongsToCollection() public async Task SaveAsync_DefaultIdWithUserId_UpdateUserInCollectionRepository(Collection collection,
Organization organization, OrganizationUser organizationUser, SutProvider<CollectionService> sutProvider)
{ {
// prepare the organization collection.Id = default;
var testOrganizationId = Guid.NewGuid(); organizationUser.Status = OrganizationUserStatusType.Confirmed;
var testOrganization = new Core.Models.Table.Organization sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
{ sutProvider.GetDependency<IOrganizationUserRepository>().GetByOrganizationAsync(organization.Id, organizationUser.Id)
Id = testOrganizationId, .Returns(organizationUser);
}; var utcNow = DateTime.UtcNow;
var testUserId = Guid.NewGuid();
var organizationUser = new Core.Models.Table.OrganizationUser
{
Id = testUserId,
OrganizationId = testOrganizationId,
};
_organizationUserRepository.GetByIdAsync(testUserId).Returns(organizationUser);
// execute await sutProvider.Sut.SaveAsync(collection, null, organizationUser.Id);
var collectionService = new CollectionService(
_eventService,
_organizationRepository,
_organizationUserRepository,
_collectionRepository,
_userRepository,
_mailService);
var testCollection = new Core.Models.Table.Collection { OrganizationId = testOrganizationId }; await sutProvider.GetDependency<ICollectionRepository>().Received().CreateAsync(collection);
await collectionService.DeleteUserAsync(testCollection, organizationUser.Id); await sutProvider.GetDependency<IOrganizationUserRepository>().Received()
.GetByOrganizationAsync(organization.Id, organizationUser.Id);
// verify await sutProvider.GetDependency<ICollectionRepository>().Received().UpdateUsersAsync(collection.Id, Arg.Any<List<SelectionReadOnly>>());
await _collectionRepository.Received().DeleteUserAsync(testCollection.Id, organizationUser.Id); await sutProvider.GetDependency<IEventService>().Received()
.LogCollectionEventAsync(collection, EventType.Collection_Created);
Assert.True(collection.CreationDate - utcNow < TimeSpan.FromSeconds(1));
Assert.True(collection.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
} }
[Fact] [Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task DeleteUserAsync_ThrowsIfUserIsInvalid() public async Task SaveAsync_NonExistingOrganizationId_ThrowsBadRequest(Collection collection, SutProvider<CollectionService> sutProvider)
{ {
// prepare the organization var ex = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SaveAsync(collection));
var testOrganizationId = Guid.NewGuid(); Assert.Contains("Organization not found", ex.Message);
var testOrganization = new Core.Models.Table.Organization await sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs().CreateAsync(default);
{ await sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs().CreateAsync(default, default);
Id = testOrganizationId, await sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
}; await sutProvider.GetDependency<IEventService>().DidNotReceiveWithAnyArgs().LogCollectionEventAsync(default, default);
var testUserId = Guid.NewGuid(); }
var nonOrganizationUser = new Core.Models.Table.OrganizationUser
{
Id = testUserId,
OrganizationId = Guid.NewGuid(),
};
_organizationUserRepository.GetByIdAsync(testUserId).Returns(nonOrganizationUser);
// execute [Theory, CollectionAutoData]
var collectionService = new CollectionService( public async Task SaveAsync_ExceedsOrganizationMaxCollections_ThrowsBadRequest(Collection collection, Collection collection1, Collection collection2, Organization organization, SutProvider<CollectionService> sutProvider)
_eventService, {
_organizationRepository, collection.Id = default;
_organizationUserRepository, sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
_collectionRepository, sutProvider.GetDependency<ICollectionRepository>().GetCountByOrganizationIdAsync(organization.Id)
_userRepository, .Returns(organization.MaxCollections.Value);
_mailService);
var testCollection = new Core.Models.Table.Collection { OrganizationId = testOrganizationId }; var ex = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SaveAsync(collection));
Assert.Equal($@"You have reached the maximum number of collections ({organization.MaxCollections.Value}) for this organization.", ex.Message);
await sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs().CreateAsync(default);
await sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs().CreateAsync(default, default);
await sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
await sutProvider.GetDependency<IEventService>().DidNotReceiveWithAnyArgs().LogCollectionEventAsync(default, default);
}
// verify [Theory, CollectionAutoData]
public async Task DeleteUserAsync_DeletesValidUserWhoBelongsToCollection(Collection collection,
Organization organization, OrganizationUser organizationUser, SutProvider<CollectionService> sutProvider)
{
collection.OrganizationId = organization.Id;
organizationUser.OrganizationId = organization.Id;
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(organizationUser.Id)
.Returns(organizationUser);
await sutProvider.Sut.DeleteUserAsync(collection, organizationUser.Id);
await sutProvider.GetDependency<ICollectionRepository>().Received()
.DeleteUserAsync(collection.Id, organizationUser.Id);
await sutProvider.GetDependency<IEventService>().Received().LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Updated);
}
[Theory, CollectionAutoData]
public async Task DeleteUserAsync_InvalidUser_ThrowsNotFound(Collection collection, Organization organization,
OrganizationUser organizationUser, SutProvider<CollectionService> sutProvider)
{
collection.OrganizationId = organization.Id;
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(organizationUser.Id)
.Returns(organizationUser);
// user not in organization
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.DeleteUserAsync(collection, organizationUser.Id));
// invalid user // invalid user
await Assert.ThrowsAsync<NotFoundException>(() => await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.DeleteUserAsync(collection, Guid.NewGuid()));
collectionService.DeleteUserAsync(testCollection, Guid.NewGuid())); await sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs().DeleteUserAsync(default, default);
// user from other organization await sutProvider.GetDependency<IEventService>().DidNotReceiveWithAnyArgs()
await Assert.ThrowsAsync<NotFoundException>(() => .LogOrganizationUserEventAsync(default, default);
collectionService.DeleteUserAsync(testCollection, testUserId));
} }
} }
} }