mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 07:36:14 -05:00
PM-13236 - Password Health Report Application - entities repos (#4974)
* PM-13236 PasswordHealthReportApplications db * PM-13236 incorporated pr comments * PM-13236 fixed error in SQL script * PM-13236 resolve quality scan errors SQL71006, SQL7101, SQL70001 * PM-13236 fixed warnings on procedures * PM-13236 added efMigrations * PM-13236 renamed files to PasswordHealthReportApplication (singular) * PM-13236 changed file name to more appropriate naming * PM-13236 changed the file name singular * PM-13236 PasswordHealthReportApplication Entities and Repos * PM-13236 moved files under tools from core * PM-13236 Entity PasswordHealthReportApplication namespace changed to tools/entities * PM-13236 moved Repos and Interfaces to tools * PM-13236 migrated model to tools namespace * PM-13236 minor fixes to the unit tests * PM-13236 fixed script errors during build * PM-13236 Script to drop PasswordHealthReportApplications if it exists * PM-13236 fixes to database snapshot * PM-13236 updated databasesnapshots * PM-13236 Update database model changes for Mysql * PM-13236 update model changes for Sqlite * PM-13236 updated the models to remove commented code * PM-13236 added correct db snapshot for MySql * PM-13236 updated database snapshot for Postgres * PM-13236 updated database snapshot for Sqlite * PM-13236 removed unwanted directive to fix linting error * PM-13236 removed redundant script files
This commit is contained in:
@ -9,6 +9,7 @@ using Bit.Infrastructure.EntityFramework.AdminConsole.Models.Provider;
|
||||
using Bit.Infrastructure.EntityFramework.Auth.Models;
|
||||
using Bit.Infrastructure.EntityFramework.Models;
|
||||
using Bit.Infrastructure.EntityFramework.Repositories;
|
||||
using Bit.Infrastructure.EntityFramework.Tools.Models;
|
||||
using Bit.Infrastructure.EntityFramework.Vault.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@ -89,6 +90,7 @@ public class EfRepositoryListBuilder<T> : ISpecimenBuilder where T : BaseEntityF
|
||||
cfg.AddProfile<TaxRateMapperProfile>();
|
||||
cfg.AddProfile<TransactionMapperProfile>();
|
||||
cfg.AddProfile<UserMapperProfile>();
|
||||
cfg.AddProfile<PasswordHealthReportApplicationProfile>();
|
||||
})
|
||||
.CreateMapper()));
|
||||
|
||||
|
@ -0,0 +1,82 @@
|
||||
using AutoFixture;
|
||||
using AutoFixture.Kernel;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Infrastructure.EntityFramework.AdminConsole.Repositories;
|
||||
using Bit.Infrastructure.EntityFramework.Repositories;
|
||||
using Bit.Infrastructure.EntityFramework.Tools.Repositories;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
namespace Bit.Infrastructure.EFIntegration.Test.AutoFixture;
|
||||
|
||||
internal class PasswordHealthReportApplicationBuilder : ISpecimenBuilder
|
||||
{
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var type = request as Type;
|
||||
if (type == null || type != typeof(PasswordHealthReportApplication))
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
var fixture = new Fixture();
|
||||
var obj = fixture.WithAutoNSubstitutions().Create<PasswordHealthReportApplication>();
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
internal class EfPasswordHealthReportApplication : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customizations.Add(new IgnoreVirtualMembersCustomization());
|
||||
fixture.Customizations.Add(new GlobalSettingsBuilder());
|
||||
fixture.Customizations.Add(new PasswordHealthReportApplicationBuilder());
|
||||
fixture.Customizations.Add(new OrganizationBuilder());
|
||||
fixture.Customizations.Add(new EfRepositoryListBuilder<PasswordHealthReportApplicationRepository>());
|
||||
fixture.Customizations.Add(new EfRepositoryListBuilder<OrganizationRepository>());
|
||||
}
|
||||
}
|
||||
|
||||
internal class EfPasswordHealthReportApplicationApplicableToUser : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customizations.Add(new IgnoreVirtualMembersCustomization());
|
||||
fixture.Customizations.Add(new GlobalSettingsBuilder());
|
||||
fixture.Customizations.Add(new PasswordHealthReportApplicationBuilder());
|
||||
fixture.Customizations.Add(new OrganizationBuilder());
|
||||
fixture.Customizations.Add(new EfRepositoryListBuilder<PasswordHealthReportApplicationRepository>());
|
||||
fixture.Customizations.Add(new EfRepositoryListBuilder<UserRepository>());
|
||||
fixture.Customizations.Add(new EfRepositoryListBuilder<OrganizationRepository>());
|
||||
fixture.Customizations.Add(new EfRepositoryListBuilder<OrganizationUserRepository>());
|
||||
fixture.Customizations.Add(new EfRepositoryListBuilder<ProviderRepository>());
|
||||
fixture.Customizations.Add(new EfRepositoryListBuilder<ProviderUserRepository>());
|
||||
fixture.Customizations.Add(new EfRepositoryListBuilder<ProviderOrganizationRepository>());
|
||||
}
|
||||
}
|
||||
|
||||
internal class EfPasswordHealthReportApplicationAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public EfPasswordHealthReportApplicationAutoDataAttribute() : base(new SutProviderCustomization(), new EfPasswordHealthReportApplication())
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class EfPasswordHealthReportApplicationApplicableToUserInlineAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public EfPasswordHealthReportApplicationApplicableToUserInlineAutoDataAttribute(params object[] values) :
|
||||
base(new[] { typeof(SutProviderCustomization), typeof(EfPasswordHealthReportApplicationApplicableToUser) }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineEfPasswordHealthReportApplicationAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineEfPasswordHealthReportApplicationAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
|
||||
typeof(EfPolicy) }, values)
|
||||
{ }
|
||||
}
|
@ -0,0 +1,269 @@
|
||||
using AutoFixture;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Test.AutoFixture.Attributes;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Tools.Repositories;
|
||||
using Bit.Infrastructure.EFIntegration.Test.AutoFixture;
|
||||
using Xunit;
|
||||
using EfRepo = Bit.Infrastructure.EntityFramework.Repositories;
|
||||
using EfToolsRepo = Bit.Infrastructure.EntityFramework.Tools.Repositories;
|
||||
using SqlAdminConsoleRepo = Bit.Infrastructure.Dapper.Tools.Repositories;
|
||||
using SqlRepo = Bit.Infrastructure.Dapper.Repositories;
|
||||
|
||||
namespace Bit.Infrastructure.EFIntegration.Test.Tools.Repositories;
|
||||
|
||||
public class PasswordHealthReportApplicationRepositoryTests
|
||||
{
|
||||
[CiSkippedTheory, EfPasswordHealthReportApplicationAutoData]
|
||||
public async Task CreateAsync_Works_DataMatches(
|
||||
PasswordHealthReportApplication passwordHealthReportApplication,
|
||||
Organization organization,
|
||||
List<EfToolsRepo.PasswordHealthReportApplicationRepository> suts,
|
||||
List<EfRepo.OrganizationRepository> efOrganizationRepos,
|
||||
SqlAdminConsoleRepo.PasswordHealthReportApplicationRepository sqlPasswordHealthReportApplicationRepo,
|
||||
SqlRepo.OrganizationRepository sqlOrganizationRepo
|
||||
)
|
||||
{
|
||||
var passwordHealthReportApplicationRecords = new List<PasswordHealthReportApplication>();
|
||||
foreach (var sut in suts)
|
||||
{
|
||||
var i = suts.IndexOf(sut);
|
||||
|
||||
var efOrganization = await efOrganizationRepos[i].CreateAsync(organization);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
passwordHealthReportApplication.OrganizationId = efOrganization.Id;
|
||||
var postEfPasswordHeathReportApp = await sut.CreateAsync(passwordHealthReportApplication);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
var savedPasswordHealthReportApplication = await sut.GetByIdAsync(postEfPasswordHeathReportApp.Id);
|
||||
passwordHealthReportApplicationRecords.Add(savedPasswordHealthReportApplication);
|
||||
}
|
||||
|
||||
var sqlOrganization = await sqlOrganizationRepo.CreateAsync(organization);
|
||||
|
||||
passwordHealthReportApplication.OrganizationId = sqlOrganization.Id;
|
||||
var sqlPasswordHealthReportApplicationRecord = await sqlPasswordHealthReportApplicationRepo.CreateAsync(passwordHealthReportApplication);
|
||||
var savedSqlPasswordHealthReportApplicationRecord = await sqlPasswordHealthReportApplicationRepo.GetByIdAsync(sqlPasswordHealthReportApplicationRecord.Id);
|
||||
passwordHealthReportApplicationRecords.Add(savedSqlPasswordHealthReportApplicationRecord);
|
||||
|
||||
Assert.True(passwordHealthReportApplicationRecords.Count == 4);
|
||||
}
|
||||
|
||||
[CiSkippedTheory, EfPasswordHealthReportApplicationAutoData]
|
||||
public async Task RetrieveByOrganisation_Works(
|
||||
SqlAdminConsoleRepo.PasswordHealthReportApplicationRepository sqlPasswordHealthReportApplicationRepo,
|
||||
SqlRepo.OrganizationRepository sqlOrganizationRepo)
|
||||
{
|
||||
var (firstOrg, firstRecord) = await CreateSampleRecord(sqlOrganizationRepo, sqlPasswordHealthReportApplicationRepo);
|
||||
var (secondOrg, secondRecord) = await CreateSampleRecord(sqlOrganizationRepo, sqlPasswordHealthReportApplicationRepo);
|
||||
|
||||
var firstSetOfRecords = await sqlPasswordHealthReportApplicationRepo.GetByOrganizationIdAsync(firstOrg.Id);
|
||||
var nextSetOfRecords = await sqlPasswordHealthReportApplicationRepo.GetByOrganizationIdAsync(secondOrg.Id);
|
||||
|
||||
Assert.True(firstSetOfRecords.Count == 1 && firstSetOfRecords.First().OrganizationId == firstOrg.Id);
|
||||
Assert.True(nextSetOfRecords.Count == 1 && nextSetOfRecords.First().OrganizationId == secondOrg.Id);
|
||||
}
|
||||
|
||||
[CiSkippedTheory, EfPasswordHealthReportApplicationAutoData]
|
||||
public async Task ReplaceQuery_Works(
|
||||
List<EfToolsRepo.PasswordHealthReportApplicationRepository> suts,
|
||||
List<EfRepo.OrganizationRepository> efOrganizationRepos,
|
||||
SqlAdminConsoleRepo.PasswordHealthReportApplicationRepository sqlPasswordHealthReportApplicationRepo,
|
||||
SqlRepo.OrganizationRepository sqlOrganizationRepo)
|
||||
{
|
||||
var (org, pwdRecord) = await CreateSampleRecord(sqlOrganizationRepo, sqlPasswordHealthReportApplicationRepo);
|
||||
var exampleUri = "http://www.example.com";
|
||||
var exampleRevisionDate = new DateTime(2021, 1, 1);
|
||||
var dbRecords = new List<PasswordHealthReportApplication>();
|
||||
|
||||
foreach (var sut in suts)
|
||||
{
|
||||
var i = suts.IndexOf(sut);
|
||||
|
||||
// create a new organization for each repository
|
||||
var organization = await efOrganizationRepos[i].CreateAsync(org);
|
||||
|
||||
// map the organization Id and create the PasswordHealthReportApp record
|
||||
pwdRecord.OrganizationId = organization.Id;
|
||||
var passwordHealthReportApplication = await sut.CreateAsync(pwdRecord);
|
||||
|
||||
// update the record with new values
|
||||
passwordHealthReportApplication.Uri = exampleUri;
|
||||
passwordHealthReportApplication.RevisionDate = exampleRevisionDate;
|
||||
|
||||
// apply update to the database
|
||||
await sut.ReplaceAsync(passwordHealthReportApplication);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
// retrieve the data and add to the list for assertions
|
||||
var recordFromDb = await sut.GetByIdAsync(passwordHealthReportApplication.Id);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
dbRecords.Add(recordFromDb);
|
||||
}
|
||||
|
||||
// sql - create a new organization and PasswordHealthReportApplication record
|
||||
var (sqlOrg, sqlPwdRecord) = await CreateSampleRecord(sqlOrganizationRepo, sqlPasswordHealthReportApplicationRepo);
|
||||
var sqlPasswordHealthReportApplicationRecord = await sqlPasswordHealthReportApplicationRepo.GetByIdAsync(sqlPwdRecord.Id);
|
||||
|
||||
// sql - update the record with new values
|
||||
sqlPasswordHealthReportApplicationRecord.Uri = exampleUri;
|
||||
sqlPasswordHealthReportApplicationRecord.RevisionDate = exampleRevisionDate;
|
||||
await sqlPasswordHealthReportApplicationRepo.ReplaceAsync(sqlPasswordHealthReportApplicationRecord);
|
||||
|
||||
// sql - retrieve the data and add to the list for assertions
|
||||
var sqlDbRecord = await sqlPasswordHealthReportApplicationRepo.GetByIdAsync(sqlPasswordHealthReportApplicationRecord.Id);
|
||||
dbRecords.Add(sqlDbRecord);
|
||||
|
||||
// assertions
|
||||
// the Guids must be distinct across all records
|
||||
Assert.True(dbRecords.Select(_ => _.Id).Distinct().Count() == dbRecords.Count);
|
||||
|
||||
// the Uri and RevisionDate must match the updated values
|
||||
Assert.True(dbRecords.All(_ => _.Uri == exampleUri && _.RevisionDate == exampleRevisionDate));
|
||||
}
|
||||
|
||||
[CiSkippedTheory, EfPasswordHealthReportApplicationAutoData]
|
||||
public async Task Upsert_Works(
|
||||
List<EfToolsRepo.PasswordHealthReportApplicationRepository> suts,
|
||||
List<EfRepo.OrganizationRepository> efOrganizationRepos,
|
||||
SqlAdminConsoleRepo.PasswordHealthReportApplicationRepository sqlPasswordHealthReportApplicationRepo,
|
||||
SqlRepo.OrganizationRepository sqlOrganizationRepo)
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
var rawOrg = fixture.Build<Organization>().Create();
|
||||
var rawPwdRecord = fixture.Build<PasswordHealthReportApplication>()
|
||||
.With(_ => _.OrganizationId, rawOrg.Id)
|
||||
.Without(_ => _.Id)
|
||||
.Create();
|
||||
var exampleUri = "http://www.example.com";
|
||||
var exampleRevisionDate = new DateTime(2021, 1, 1);
|
||||
var dbRecords = new List<PasswordHealthReportApplication>();
|
||||
|
||||
foreach (var sut in suts)
|
||||
{
|
||||
var i = suts.IndexOf(sut);
|
||||
|
||||
// create a new organization for each repository
|
||||
var organization = await efOrganizationRepos[i].CreateAsync(rawOrg);
|
||||
|
||||
// map the organization Id and use Upsert to save new record
|
||||
rawPwdRecord.OrganizationId = organization.Id;
|
||||
rawPwdRecord.Id = default(Guid);
|
||||
await sut.UpsertAsync(rawPwdRecord);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
// retrieve the data and add to the list for assertions
|
||||
var passwordHealthReportApplication = await sut.GetByIdAsync(rawPwdRecord.Id);
|
||||
|
||||
// update the record with new values
|
||||
passwordHealthReportApplication.Uri = exampleUri;
|
||||
passwordHealthReportApplication.RevisionDate = exampleRevisionDate;
|
||||
|
||||
// apply update using Upsert to make changes to db
|
||||
await sut.UpsertAsync(passwordHealthReportApplication);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
// retrieve the data and add to the list for assertions
|
||||
var recordFromDb = await sut.GetByIdAsync(passwordHealthReportApplication.Id);
|
||||
dbRecords.Add(recordFromDb);
|
||||
|
||||
sut.ClearChangeTracking();
|
||||
}
|
||||
|
||||
// sql - create new records
|
||||
var organizationForSql = fixture.Create<Organization>();
|
||||
var passwordHealthReportApplicationForSql = fixture.Build<PasswordHealthReportApplication>()
|
||||
.With(_ => _.OrganizationId, organizationForSql.Id)
|
||||
.Without(_ => _.Id)
|
||||
.Create();
|
||||
|
||||
// sql - use Upsert to insert this data
|
||||
var sqlOrganization = await sqlOrganizationRepo.CreateAsync(organizationForSql);
|
||||
await sqlPasswordHealthReportApplicationRepo.UpsertAsync(passwordHealthReportApplicationForSql);
|
||||
var sqlPasswordHealthReportApplicationRecord = await sqlPasswordHealthReportApplicationRepo.GetByIdAsync(passwordHealthReportApplicationForSql.Id);
|
||||
|
||||
// sql - update the record with new values
|
||||
sqlPasswordHealthReportApplicationRecord.Uri = exampleUri;
|
||||
sqlPasswordHealthReportApplicationRecord.RevisionDate = exampleRevisionDate;
|
||||
await sqlPasswordHealthReportApplicationRepo.UpsertAsync(sqlPasswordHealthReportApplicationRecord);
|
||||
|
||||
// sql - retrieve the data and add to the list for assertions
|
||||
var sqlDbRecord = await sqlPasswordHealthReportApplicationRepo.GetByIdAsync(sqlPasswordHealthReportApplicationRecord.Id);
|
||||
dbRecords.Add(sqlDbRecord);
|
||||
|
||||
// assertions
|
||||
// the Guids must be distinct across all records
|
||||
Assert.True(dbRecords.Select(_ => _.Id).Distinct().Count() == dbRecords.Count);
|
||||
|
||||
// the Uri and RevisionDate must match the updated values
|
||||
Assert.True(dbRecords.All(_ => _.Uri == exampleUri && _.RevisionDate == exampleRevisionDate));
|
||||
}
|
||||
|
||||
[CiSkippedTheory, EfPasswordHealthReportApplicationAutoData]
|
||||
public async Task Delete_Works(
|
||||
List<EfToolsRepo.PasswordHealthReportApplicationRepository> suts,
|
||||
List<EfRepo.OrganizationRepository> efOrganizationRepos,
|
||||
SqlAdminConsoleRepo.PasswordHealthReportApplicationRepository sqlPasswordHealthReportApplicationRepo,
|
||||
SqlRepo.OrganizationRepository sqlOrganizationRepo)
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
var rawOrg = fixture.Build<Organization>().Create();
|
||||
var rawPwdRecord = fixture.Build<PasswordHealthReportApplication>()
|
||||
.With(_ => _.OrganizationId, rawOrg.Id)
|
||||
.Create();
|
||||
var dbRecords = new List<PasswordHealthReportApplication>();
|
||||
|
||||
foreach (var sut in suts)
|
||||
{
|
||||
var i = suts.IndexOf(sut);
|
||||
|
||||
// create a new organization for each repository
|
||||
var organization = await efOrganizationRepos[i].CreateAsync(rawOrg);
|
||||
|
||||
// map the organization Id and use Upsert to save new record
|
||||
rawPwdRecord.OrganizationId = organization.Id;
|
||||
rawPwdRecord = await sut.CreateAsync(rawPwdRecord);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
// apply update using Upsert to make changes to db
|
||||
await sut.DeleteAsync(rawPwdRecord);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
// retrieve the data and add to the list for assertions
|
||||
var recordFromDb = await sut.GetByIdAsync(rawPwdRecord.Id);
|
||||
dbRecords.Add(recordFromDb);
|
||||
|
||||
sut.ClearChangeTracking();
|
||||
}
|
||||
|
||||
// sql - create new records
|
||||
var (org, passwordHealthReportApplication) = await CreateSampleRecord(sqlOrganizationRepo, sqlPasswordHealthReportApplicationRepo);
|
||||
await sqlPasswordHealthReportApplicationRepo.DeleteAsync(passwordHealthReportApplication);
|
||||
var sqlDbRecord = await sqlPasswordHealthReportApplicationRepo.GetByIdAsync(passwordHealthReportApplication.Id);
|
||||
dbRecords.Add(sqlDbRecord);
|
||||
|
||||
// assertions
|
||||
// all records should be null - as they were deleted before querying
|
||||
Assert.True(dbRecords.Where(_ => _ == null).Count() == 4);
|
||||
}
|
||||
|
||||
private async Task<(Organization, PasswordHealthReportApplication)> CreateSampleRecord(
|
||||
IOrganizationRepository organizationRepo,
|
||||
IPasswordHealthReportApplicationRepository passwordHealthReportApplicationRepo
|
||||
)
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
var organization = fixture.Create<Organization>();
|
||||
var passwordHealthReportApplication = fixture.Build<PasswordHealthReportApplication>()
|
||||
.With(_ => _.OrganizationId, organization.Id)
|
||||
.Create();
|
||||
|
||||
organization = await organizationRepo.CreateAsync(organization);
|
||||
passwordHealthReportApplication = await passwordHealthReportApplicationRepo.CreateAsync(passwordHealthReportApplication);
|
||||
|
||||
return (organization, passwordHealthReportApplication);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user