mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 07:36:14 -05:00
Turn on file scoped namespaces (#2225)
This commit is contained in:
@ -3,42 +3,41 @@ using Bit.IntegrationTestCommon.Factories;
|
||||
using IdentityServer4.AccessTokenValidation;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
|
||||
namespace Bit.Api.IntegrationTest.Factories
|
||||
namespace Bit.Api.IntegrationTest.Factories;
|
||||
|
||||
public class ApiApplicationFactory : WebApplicationFactoryBase<Startup>
|
||||
{
|
||||
public class ApiApplicationFactory : WebApplicationFactoryBase<Startup>
|
||||
private readonly IdentityApplicationFactory _identityApplicationFactory;
|
||||
|
||||
public ApiApplicationFactory()
|
||||
{
|
||||
private readonly IdentityApplicationFactory _identityApplicationFactory;
|
||||
_identityApplicationFactory = new IdentityApplicationFactory();
|
||||
}
|
||||
|
||||
public ApiApplicationFactory()
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
{
|
||||
base.ConfigureWebHost(builder);
|
||||
|
||||
builder.ConfigureTestServices(services =>
|
||||
{
|
||||
_identityApplicationFactory = new IdentityApplicationFactory();
|
||||
}
|
||||
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
{
|
||||
base.ConfigureWebHost(builder);
|
||||
|
||||
builder.ConfigureTestServices(services =>
|
||||
services.PostConfigure<IdentityServerAuthenticationOptions>(IdentityServerAuthenticationDefaults.AuthenticationScheme, options =>
|
||||
{
|
||||
services.PostConfigure<IdentityServerAuthenticationOptions>(IdentityServerAuthenticationDefaults.AuthenticationScheme, options =>
|
||||
{
|
||||
options.JwtBackChannelHandler = _identityApplicationFactory.Server.CreateHandler();
|
||||
});
|
||||
options.JwtBackChannelHandler = _identityApplicationFactory.Server.CreateHandler();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for registering and logging in to a new account
|
||||
/// </summary>
|
||||
public async Task<(string Token, string RefreshToken)> LoginWithNewAccount(string email = "integration-test@bitwarden.com", string masterPasswordHash = "master_password_hash")
|
||||
/// <summary>
|
||||
/// Helper for registering and logging in to a new account
|
||||
/// </summary>
|
||||
public async Task<(string Token, string RefreshToken)> LoginWithNewAccount(string email = "integration-test@bitwarden.com", string masterPasswordHash = "master_password_hash")
|
||||
{
|
||||
await _identityApplicationFactory.RegisterAsync(new RegisterRequestModel
|
||||
{
|
||||
await _identityApplicationFactory.RegisterAsync(new RegisterRequestModel
|
||||
{
|
||||
Email = email,
|
||||
MasterPasswordHash = masterPasswordHash,
|
||||
});
|
||||
Email = email,
|
||||
MasterPasswordHash = masterPasswordHash,
|
||||
});
|
||||
|
||||
return await _identityApplicationFactory.TokenFromPasswordAsync(email, masterPasswordHash);
|
||||
}
|
||||
return await _identityApplicationFactory.TokenFromPasswordAsync(email, masterPasswordHash);
|
||||
}
|
||||
}
|
||||
|
@ -13,413 +13,412 @@ using Microsoft.AspNetCore.Identity;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Controllers
|
||||
namespace Bit.Api.Test.Controllers;
|
||||
|
||||
public class AccountsControllerTests : IDisposable
|
||||
{
|
||||
public class AccountsControllerTests : IDisposable
|
||||
|
||||
private readonly AccountsController _sut;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ICipherRepository _cipherRepository;
|
||||
private readonly IFolderRepository _folderRepository;
|
||||
private readonly IOrganizationService _organizationService;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IPaymentService _paymentService;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IUserService _userService;
|
||||
private readonly ISendRepository _sendRepository;
|
||||
private readonly ISendService _sendService;
|
||||
private readonly IProviderUserRepository _providerUserRepository;
|
||||
|
||||
public AccountsControllerTests()
|
||||
{
|
||||
_userService = Substitute.For<IUserService>();
|
||||
_userRepository = Substitute.For<IUserRepository>();
|
||||
_cipherRepository = Substitute.For<ICipherRepository>();
|
||||
_folderRepository = Substitute.For<IFolderRepository>();
|
||||
_organizationService = Substitute.For<IOrganizationService>();
|
||||
_organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
|
||||
_providerUserRepository = Substitute.For<IProviderUserRepository>();
|
||||
_paymentService = Substitute.For<IPaymentService>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
_sendRepository = Substitute.For<ISendRepository>();
|
||||
_sendService = Substitute.For<ISendService>();
|
||||
_sut = new AccountsController(
|
||||
_globalSettings,
|
||||
_cipherRepository,
|
||||
_folderRepository,
|
||||
_organizationService,
|
||||
_organizationUserRepository,
|
||||
_providerUserRepository,
|
||||
_paymentService,
|
||||
_userRepository,
|
||||
_userService,
|
||||
_sendRepository,
|
||||
_sendService
|
||||
);
|
||||
}
|
||||
|
||||
private readonly AccountsController _sut;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ICipherRepository _cipherRepository;
|
||||
private readonly IFolderRepository _folderRepository;
|
||||
private readonly IOrganizationService _organizationService;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IPaymentService _paymentService;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IUserService _userService;
|
||||
private readonly ISendRepository _sendRepository;
|
||||
private readonly ISendService _sendService;
|
||||
private readonly IProviderUserRepository _providerUserRepository;
|
||||
public void Dispose()
|
||||
{
|
||||
_sut?.Dispose();
|
||||
}
|
||||
|
||||
public AccountsControllerTests()
|
||||
[Fact]
|
||||
public async Task PostPrelogin_WhenUserExists_ShouldReturnUserKdfInfo()
|
||||
{
|
||||
var userKdfInfo = new UserKdfInformation
|
||||
{
|
||||
_userService = Substitute.For<IUserService>();
|
||||
_userRepository = Substitute.For<IUserRepository>();
|
||||
_cipherRepository = Substitute.For<ICipherRepository>();
|
||||
_folderRepository = Substitute.For<IFolderRepository>();
|
||||
_organizationService = Substitute.For<IOrganizationService>();
|
||||
_organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
|
||||
_providerUserRepository = Substitute.For<IProviderUserRepository>();
|
||||
_paymentService = Substitute.For<IPaymentService>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
_sendRepository = Substitute.For<ISendRepository>();
|
||||
_sendService = Substitute.For<ISendService>();
|
||||
_sut = new AccountsController(
|
||||
_globalSettings,
|
||||
_cipherRepository,
|
||||
_folderRepository,
|
||||
_organizationService,
|
||||
_organizationUserRepository,
|
||||
_providerUserRepository,
|
||||
_paymentService,
|
||||
_userRepository,
|
||||
_userService,
|
||||
_sendRepository,
|
||||
_sendService
|
||||
);
|
||||
}
|
||||
Kdf = KdfType.PBKDF2_SHA256,
|
||||
KdfIterations = 5000
|
||||
};
|
||||
_userRepository.GetKdfInformationByEmailAsync(Arg.Any<string>()).Returns(Task.FromResult(userKdfInfo));
|
||||
|
||||
public void Dispose()
|
||||
var response = await _sut.PostPrelogin(new PreloginRequestModel { Email = "user@example.com" });
|
||||
|
||||
Assert.Equal(userKdfInfo.Kdf, response.Kdf);
|
||||
Assert.Equal(userKdfInfo.KdfIterations, response.KdfIterations);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostPrelogin_WhenUserDoesNotExist_ShouldDefaultToSha256And100000Iterations()
|
||||
{
|
||||
_userRepository.GetKdfInformationByEmailAsync(Arg.Any<string>()).Returns(Task.FromResult((UserKdfInformation)null));
|
||||
|
||||
var response = await _sut.PostPrelogin(new PreloginRequestModel { Email = "user@example.com" });
|
||||
|
||||
Assert.Equal(KdfType.PBKDF2_SHA256, response.Kdf);
|
||||
Assert.Equal(100000, response.KdfIterations);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostRegister_ShouldRegisterUser()
|
||||
{
|
||||
var passwordHash = "abcdef";
|
||||
var token = "123456";
|
||||
var userGuid = new Guid();
|
||||
_userService.RegisterUserAsync(Arg.Any<User>(), passwordHash, token, userGuid)
|
||||
.Returns(Task.FromResult(IdentityResult.Success));
|
||||
var request = new RegisterRequestModel
|
||||
{
|
||||
_sut?.Dispose();
|
||||
}
|
||||
Name = "Example User",
|
||||
Email = "user@example.com",
|
||||
MasterPasswordHash = passwordHash,
|
||||
MasterPasswordHint = "example",
|
||||
Token = token,
|
||||
OrganizationUserId = userGuid
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public async Task PostPrelogin_WhenUserExists_ShouldReturnUserKdfInfo()
|
||||
await _sut.PostRegister(request);
|
||||
|
||||
await _userService.Received(1).RegisterUserAsync(Arg.Any<User>(), passwordHash, token, userGuid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostRegister_WhenUserServiceFails_ShouldThrowBadRequestException()
|
||||
{
|
||||
var passwordHash = "abcdef";
|
||||
var token = "123456";
|
||||
var userGuid = new Guid();
|
||||
_userService.RegisterUserAsync(Arg.Any<User>(), passwordHash, token, userGuid)
|
||||
.Returns(Task.FromResult(IdentityResult.Failed()));
|
||||
var request = new RegisterRequestModel
|
||||
{
|
||||
var userKdfInfo = new UserKdfInformation
|
||||
{
|
||||
Kdf = KdfType.PBKDF2_SHA256,
|
||||
KdfIterations = 5000
|
||||
};
|
||||
_userRepository.GetKdfInformationByEmailAsync(Arg.Any<string>()).Returns(Task.FromResult(userKdfInfo));
|
||||
Name = "Example User",
|
||||
Email = "user@example.com",
|
||||
MasterPasswordHash = passwordHash,
|
||||
MasterPasswordHint = "example",
|
||||
Token = token,
|
||||
OrganizationUserId = userGuid
|
||||
};
|
||||
|
||||
var response = await _sut.PostPrelogin(new PreloginRequestModel { Email = "user@example.com" });
|
||||
await Assert.ThrowsAsync<BadRequestException>(() => _sut.PostRegister(request));
|
||||
}
|
||||
|
||||
Assert.Equal(userKdfInfo.Kdf, response.Kdf);
|
||||
Assert.Equal(userKdfInfo.KdfIterations, response.KdfIterations);
|
||||
}
|
||||
[Fact]
|
||||
public async Task PostPasswordHint_ShouldNotifyUserService()
|
||||
{
|
||||
var email = "user@example.com";
|
||||
|
||||
[Fact]
|
||||
public async Task PostPrelogin_WhenUserDoesNotExist_ShouldDefaultToSha256And100000Iterations()
|
||||
await _sut.PostPasswordHint(new PasswordHintRequestModel { Email = email });
|
||||
|
||||
await _userService.Received(1).SendMasterPasswordHintAsync(email);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostEmailToken_ShouldInitiateEmailChange()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
ConfigureUserServiceToAcceptPasswordFor(user);
|
||||
var newEmail = "example@user.com";
|
||||
|
||||
await _sut.PostEmailToken(new EmailTokenRequestModel { NewEmail = newEmail });
|
||||
|
||||
await _userService.Received(1).InitiateEmailChangeAsync(user, newEmail);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostEmailToken_WhenNotAuthorized_ShouldThrowUnauthorizedAccessException()
|
||||
{
|
||||
ConfigureUserServiceToReturnNullPrincipal();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.PostEmailToken(new EmailTokenRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostEmailToken_WhenInvalidPasssword_ShouldThrowBadRequestException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
ConfigureUserServiceToRejectPasswordFor(user);
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.PostEmailToken(new EmailTokenRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostEmail_ShouldChangeUserEmail()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
_userService.ChangeEmailAsync(user, default, default, default, default, default)
|
||||
.Returns(Task.FromResult(IdentityResult.Success));
|
||||
|
||||
await _sut.PostEmail(new EmailRequestModel());
|
||||
|
||||
await _userService.Received(1).ChangeEmailAsync(user, default, default, default, default, default);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostEmail_WhenNotAuthorized_ShouldThrownUnauthorizedAccessException()
|
||||
{
|
||||
ConfigureUserServiceToReturnNullPrincipal();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.PostEmail(new EmailRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostEmail_WhenEmailCannotBeChanged_ShouldThrowBadRequestException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
_userService.ChangeEmailAsync(user, default, default, default, default, default)
|
||||
.Returns(Task.FromResult(IdentityResult.Failed()));
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.PostEmail(new EmailRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostVerifyEmail_ShouldSendEmailVerification()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
|
||||
await _sut.PostVerifyEmail();
|
||||
|
||||
await _userService.Received(1).SendEmailVerificationAsync(user);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostVerifyEmail_WhenNotAuthorized_ShouldThrownUnauthorizedAccessException()
|
||||
{
|
||||
ConfigureUserServiceToReturnNullPrincipal();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.PostVerifyEmail()
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostVerifyEmailToken_ShouldConfirmEmail()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidIdFor(user);
|
||||
_userService.ConfirmEmailAsync(user, Arg.Any<string>())
|
||||
.Returns(Task.FromResult(IdentityResult.Success));
|
||||
|
||||
await _sut.PostVerifyEmailToken(new VerifyEmailRequestModel { UserId = "12345678-1234-1234-1234-123456789012" });
|
||||
|
||||
await _userService.Received(1).ConfirmEmailAsync(user, Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostVerifyEmailToken_WhenUserDoesNotExist_ShouldThrowUnauthorizedAccessException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnNullUserId();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.PostVerifyEmailToken(new VerifyEmailRequestModel { UserId = "12345678-1234-1234-1234-123456789012" })
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostVerifyEmailToken_WhenEmailConfirmationFails_ShouldThrowBadRequestException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidIdFor(user);
|
||||
_userService.ConfirmEmailAsync(user, Arg.Any<string>())
|
||||
.Returns(Task.FromResult(IdentityResult.Failed()));
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.PostVerifyEmailToken(new VerifyEmailRequestModel { UserId = "12345678-1234-1234-1234-123456789012" })
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostPassword_ShouldChangePassword()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
_userService.ChangePasswordAsync(user, default, default, default, default)
|
||||
.Returns(Task.FromResult(IdentityResult.Success));
|
||||
|
||||
await _sut.PostPassword(new PasswordRequestModel());
|
||||
|
||||
await _userService.Received(1).ChangePasswordAsync(user, default, default, default, default);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostPassword_WhenNotAuthorized_ShouldThrowUnauthorizedAccessException()
|
||||
{
|
||||
ConfigureUserServiceToReturnNullPrincipal();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.PostPassword(new PasswordRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostPassword_WhenPasswordChangeFails_ShouldBadRequestException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
_userService.ChangePasswordAsync(user, default, default, default, default)
|
||||
.Returns(Task.FromResult(IdentityResult.Failed()));
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.PostPassword(new PasswordRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetApiKey_ShouldReturnApiKeyResponse()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
ConfigureUserServiceToAcceptPasswordFor(user);
|
||||
await _sut.ApiKey(new SecretVerificationRequestModel());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetApiKey_WhenUserDoesNotExist_ShouldThrowUnauthorizedAccessException()
|
||||
{
|
||||
ConfigureUserServiceToReturnNullPrincipal();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.ApiKey(new SecretVerificationRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetApiKey_WhenPasswordCheckFails_ShouldThrowBadRequestException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
ConfigureUserServiceToRejectPasswordFor(user);
|
||||
await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.ApiKey(new SecretVerificationRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostRotateApiKey_ShouldRotateApiKey()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
ConfigureUserServiceToAcceptPasswordFor(user);
|
||||
await _sut.RotateApiKey(new SecretVerificationRequestModel());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostRotateApiKey_WhenUserDoesNotExist_ShouldThrowUnauthorizedAccessException()
|
||||
{
|
||||
ConfigureUserServiceToReturnNullPrincipal();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.ApiKey(new SecretVerificationRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostRotateApiKey_WhenPasswordCheckFails_ShouldThrowBadRequestException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
ConfigureUserServiceToRejectPasswordFor(user);
|
||||
await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.ApiKey(new SecretVerificationRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
// Below are helper functions that currently belong to this
|
||||
// test class, but ultimately may need to be split out into
|
||||
// something greater in order to share common test steps with
|
||||
// other test suites. They are included here for the time being
|
||||
// until that day comes.
|
||||
private User GenerateExampleUser()
|
||||
{
|
||||
return new User
|
||||
{
|
||||
_userRepository.GetKdfInformationByEmailAsync(Arg.Any<string>()).Returns(Task.FromResult((UserKdfInformation)null));
|
||||
Email = "user@example.com"
|
||||
};
|
||||
}
|
||||
|
||||
var response = await _sut.PostPrelogin(new PreloginRequestModel { Email = "user@example.com" });
|
||||
private void ConfigureUserServiceToReturnNullPrincipal()
|
||||
{
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>())
|
||||
.Returns(Task.FromResult((User)null));
|
||||
}
|
||||
|
||||
Assert.Equal(KdfType.PBKDF2_SHA256, response.Kdf);
|
||||
Assert.Equal(100000, response.KdfIterations);
|
||||
}
|
||||
private void ConfigureUserServiceToReturnValidPrincipalFor(User user)
|
||||
{
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>())
|
||||
.Returns(Task.FromResult(user));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostRegister_ShouldRegisterUser()
|
||||
{
|
||||
var passwordHash = "abcdef";
|
||||
var token = "123456";
|
||||
var userGuid = new Guid();
|
||||
_userService.RegisterUserAsync(Arg.Any<User>(), passwordHash, token, userGuid)
|
||||
.Returns(Task.FromResult(IdentityResult.Success));
|
||||
var request = new RegisterRequestModel
|
||||
{
|
||||
Name = "Example User",
|
||||
Email = "user@example.com",
|
||||
MasterPasswordHash = passwordHash,
|
||||
MasterPasswordHint = "example",
|
||||
Token = token,
|
||||
OrganizationUserId = userGuid
|
||||
};
|
||||
private void ConfigureUserServiceToRejectPasswordFor(User user)
|
||||
{
|
||||
_userService.CheckPasswordAsync(user, Arg.Any<string>())
|
||||
.Returns(Task.FromResult(false));
|
||||
}
|
||||
|
||||
await _sut.PostRegister(request);
|
||||
private void ConfigureUserServiceToAcceptPasswordFor(User user)
|
||||
{
|
||||
_userService.CheckPasswordAsync(user, Arg.Any<string>())
|
||||
.Returns(Task.FromResult(true));
|
||||
_userService.VerifySecretAsync(user, Arg.Any<string>())
|
||||
.Returns(Task.FromResult(true));
|
||||
}
|
||||
|
||||
await _userService.Received(1).RegisterUserAsync(Arg.Any<User>(), passwordHash, token, userGuid);
|
||||
}
|
||||
private void ConfigureUserServiceToReturnValidIdFor(User user)
|
||||
{
|
||||
_userService.GetUserByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(Task.FromResult(user));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostRegister_WhenUserServiceFails_ShouldThrowBadRequestException()
|
||||
{
|
||||
var passwordHash = "abcdef";
|
||||
var token = "123456";
|
||||
var userGuid = new Guid();
|
||||
_userService.RegisterUserAsync(Arg.Any<User>(), passwordHash, token, userGuid)
|
||||
.Returns(Task.FromResult(IdentityResult.Failed()));
|
||||
var request = new RegisterRequestModel
|
||||
{
|
||||
Name = "Example User",
|
||||
Email = "user@example.com",
|
||||
MasterPasswordHash = passwordHash,
|
||||
MasterPasswordHint = "example",
|
||||
Token = token,
|
||||
OrganizationUserId = userGuid
|
||||
};
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(() => _sut.PostRegister(request));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostPasswordHint_ShouldNotifyUserService()
|
||||
{
|
||||
var email = "user@example.com";
|
||||
|
||||
await _sut.PostPasswordHint(new PasswordHintRequestModel { Email = email });
|
||||
|
||||
await _userService.Received(1).SendMasterPasswordHintAsync(email);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostEmailToken_ShouldInitiateEmailChange()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
ConfigureUserServiceToAcceptPasswordFor(user);
|
||||
var newEmail = "example@user.com";
|
||||
|
||||
await _sut.PostEmailToken(new EmailTokenRequestModel { NewEmail = newEmail });
|
||||
|
||||
await _userService.Received(1).InitiateEmailChangeAsync(user, newEmail);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostEmailToken_WhenNotAuthorized_ShouldThrowUnauthorizedAccessException()
|
||||
{
|
||||
ConfigureUserServiceToReturnNullPrincipal();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.PostEmailToken(new EmailTokenRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostEmailToken_WhenInvalidPasssword_ShouldThrowBadRequestException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
ConfigureUserServiceToRejectPasswordFor(user);
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.PostEmailToken(new EmailTokenRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostEmail_ShouldChangeUserEmail()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
_userService.ChangeEmailAsync(user, default, default, default, default, default)
|
||||
.Returns(Task.FromResult(IdentityResult.Success));
|
||||
|
||||
await _sut.PostEmail(new EmailRequestModel());
|
||||
|
||||
await _userService.Received(1).ChangeEmailAsync(user, default, default, default, default, default);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostEmail_WhenNotAuthorized_ShouldThrownUnauthorizedAccessException()
|
||||
{
|
||||
ConfigureUserServiceToReturnNullPrincipal();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.PostEmail(new EmailRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostEmail_WhenEmailCannotBeChanged_ShouldThrowBadRequestException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
_userService.ChangeEmailAsync(user, default, default, default, default, default)
|
||||
.Returns(Task.FromResult(IdentityResult.Failed()));
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.PostEmail(new EmailRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostVerifyEmail_ShouldSendEmailVerification()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
|
||||
await _sut.PostVerifyEmail();
|
||||
|
||||
await _userService.Received(1).SendEmailVerificationAsync(user);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostVerifyEmail_WhenNotAuthorized_ShouldThrownUnauthorizedAccessException()
|
||||
{
|
||||
ConfigureUserServiceToReturnNullPrincipal();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.PostVerifyEmail()
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostVerifyEmailToken_ShouldConfirmEmail()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidIdFor(user);
|
||||
_userService.ConfirmEmailAsync(user, Arg.Any<string>())
|
||||
.Returns(Task.FromResult(IdentityResult.Success));
|
||||
|
||||
await _sut.PostVerifyEmailToken(new VerifyEmailRequestModel { UserId = "12345678-1234-1234-1234-123456789012" });
|
||||
|
||||
await _userService.Received(1).ConfirmEmailAsync(user, Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostVerifyEmailToken_WhenUserDoesNotExist_ShouldThrowUnauthorizedAccessException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnNullUserId();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.PostVerifyEmailToken(new VerifyEmailRequestModel { UserId = "12345678-1234-1234-1234-123456789012" })
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostVerifyEmailToken_WhenEmailConfirmationFails_ShouldThrowBadRequestException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidIdFor(user);
|
||||
_userService.ConfirmEmailAsync(user, Arg.Any<string>())
|
||||
.Returns(Task.FromResult(IdentityResult.Failed()));
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.PostVerifyEmailToken(new VerifyEmailRequestModel { UserId = "12345678-1234-1234-1234-123456789012" })
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostPassword_ShouldChangePassword()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
_userService.ChangePasswordAsync(user, default, default, default, default)
|
||||
.Returns(Task.FromResult(IdentityResult.Success));
|
||||
|
||||
await _sut.PostPassword(new PasswordRequestModel());
|
||||
|
||||
await _userService.Received(1).ChangePasswordAsync(user, default, default, default, default);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostPassword_WhenNotAuthorized_ShouldThrowUnauthorizedAccessException()
|
||||
{
|
||||
ConfigureUserServiceToReturnNullPrincipal();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.PostPassword(new PasswordRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostPassword_WhenPasswordChangeFails_ShouldBadRequestException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
_userService.ChangePasswordAsync(user, default, default, default, default)
|
||||
.Returns(Task.FromResult(IdentityResult.Failed()));
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.PostPassword(new PasswordRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetApiKey_ShouldReturnApiKeyResponse()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
ConfigureUserServiceToAcceptPasswordFor(user);
|
||||
await _sut.ApiKey(new SecretVerificationRequestModel());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetApiKey_WhenUserDoesNotExist_ShouldThrowUnauthorizedAccessException()
|
||||
{
|
||||
ConfigureUserServiceToReturnNullPrincipal();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.ApiKey(new SecretVerificationRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetApiKey_WhenPasswordCheckFails_ShouldThrowBadRequestException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
ConfigureUserServiceToRejectPasswordFor(user);
|
||||
await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.ApiKey(new SecretVerificationRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostRotateApiKey_ShouldRotateApiKey()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
ConfigureUserServiceToAcceptPasswordFor(user);
|
||||
await _sut.RotateApiKey(new SecretVerificationRequestModel());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostRotateApiKey_WhenUserDoesNotExist_ShouldThrowUnauthorizedAccessException()
|
||||
{
|
||||
ConfigureUserServiceToReturnNullPrincipal();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(
|
||||
() => _sut.ApiKey(new SecretVerificationRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostRotateApiKey_WhenPasswordCheckFails_ShouldThrowBadRequestException()
|
||||
{
|
||||
var user = GenerateExampleUser();
|
||||
ConfigureUserServiceToReturnValidPrincipalFor(user);
|
||||
ConfigureUserServiceToRejectPasswordFor(user);
|
||||
await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.ApiKey(new SecretVerificationRequestModel())
|
||||
);
|
||||
}
|
||||
|
||||
// Below are helper functions that currently belong to this
|
||||
// test class, but ultimately may need to be split out into
|
||||
// something greater in order to share common test steps with
|
||||
// other test suites. They are included here for the time being
|
||||
// until that day comes.
|
||||
private User GenerateExampleUser()
|
||||
{
|
||||
return new User
|
||||
{
|
||||
Email = "user@example.com"
|
||||
};
|
||||
}
|
||||
|
||||
private void ConfigureUserServiceToReturnNullPrincipal()
|
||||
{
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>())
|
||||
.Returns(Task.FromResult((User)null));
|
||||
}
|
||||
|
||||
private void ConfigureUserServiceToReturnValidPrincipalFor(User user)
|
||||
{
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>())
|
||||
.Returns(Task.FromResult(user));
|
||||
}
|
||||
|
||||
private void ConfigureUserServiceToRejectPasswordFor(User user)
|
||||
{
|
||||
_userService.CheckPasswordAsync(user, Arg.Any<string>())
|
||||
.Returns(Task.FromResult(false));
|
||||
}
|
||||
|
||||
private void ConfigureUserServiceToAcceptPasswordFor(User user)
|
||||
{
|
||||
_userService.CheckPasswordAsync(user, Arg.Any<string>())
|
||||
.Returns(Task.FromResult(true));
|
||||
_userService.VerifySecretAsync(user, Arg.Any<string>())
|
||||
.Returns(Task.FromResult(true));
|
||||
}
|
||||
|
||||
private void ConfigureUserServiceToReturnValidIdFor(User user)
|
||||
{
|
||||
_userService.GetUserByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(Task.FromResult(user));
|
||||
}
|
||||
|
||||
private void ConfigureUserServiceToReturnNullUserId()
|
||||
{
|
||||
_userService.GetUserByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(Task.FromResult((User)null));
|
||||
}
|
||||
private void ConfigureUserServiceToReturnNullUserId()
|
||||
{
|
||||
_userService.GetUserByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(Task.FromResult((User)null));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,79 +11,78 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Controllers
|
||||
namespace Bit.Api.Test.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(CollectionsController))]
|
||||
[SutProviderCustomize]
|
||||
public class CollectionsControllerTests
|
||||
{
|
||||
[ControllerCustomize(typeof(CollectionsController))]
|
||||
[SutProviderCustomize]
|
||||
public class CollectionsControllerTests
|
||||
[Theory, BitAutoData]
|
||||
public async Task Post_Success(Guid orgId, SutProvider<CollectionsController> sutProvider)
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
public async Task Post_Success(Guid orgId, SutProvider<CollectionsController> sutProvider)
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.CreateNewCollections(orgId)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.EditAnyCollection(orgId)
|
||||
.Returns(false);
|
||||
|
||||
var collectionRequest = new CollectionRequestModel
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.CreateNewCollections(orgId)
|
||||
.Returns(true);
|
||||
Name = "encrypted_string",
|
||||
ExternalId = "my_external_id"
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.EditAnyCollection(orgId)
|
||||
.Returns(false);
|
||||
_ = await sutProvider.Sut.Post(orgId, collectionRequest);
|
||||
|
||||
var collectionRequest = new CollectionRequestModel
|
||||
await sutProvider.GetDependency<ICollectionService>()
|
||||
.Received(1)
|
||||
.SaveAsync(Arg.Any<Collection>(), Arg.Any<IEnumerable<SelectionReadOnly>>(), null);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task Put_Success(Guid orgId, Guid collectionId, Guid userId, CollectionRequestModel collectionRequest,
|
||||
SutProvider<CollectionsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.ViewAssignedCollections(orgId)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.EditAssignedCollections(orgId)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.UserId
|
||||
.Returns(userId);
|
||||
|
||||
sutProvider.GetDependency<ICollectionRepository>()
|
||||
.GetByIdAsync(collectionId, userId)
|
||||
.Returns(new CollectionDetails
|
||||
{
|
||||
Name = "encrypted_string",
|
||||
ExternalId = "my_external_id"
|
||||
};
|
||||
OrganizationId = orgId,
|
||||
});
|
||||
|
||||
_ = await sutProvider.Sut.Post(orgId, collectionRequest);
|
||||
_ = await sutProvider.Sut.Put(orgId, collectionId, collectionRequest);
|
||||
}
|
||||
|
||||
await sutProvider.GetDependency<ICollectionService>()
|
||||
.Received(1)
|
||||
.SaveAsync(Arg.Any<Collection>(), Arg.Any<IEnumerable<SelectionReadOnly>>(), null);
|
||||
}
|
||||
[Theory, BitAutoData]
|
||||
public async Task Put_CanNotEditAssignedCollection_ThrowsNotFound(Guid orgId, Guid collectionId, Guid userId, CollectionRequestModel collectionRequest,
|
||||
SutProvider<CollectionsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.EditAssignedCollections(orgId)
|
||||
.Returns(true);
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task Put_Success(Guid orgId, Guid collectionId, Guid userId, CollectionRequestModel collectionRequest,
|
||||
SutProvider<CollectionsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.ViewAssignedCollections(orgId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.UserId
|
||||
.Returns(userId);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.EditAssignedCollections(orgId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<ICollectionRepository>()
|
||||
.GetByIdAsync(collectionId, userId)
|
||||
.Returns(Task.FromResult<CollectionDetails>(null));
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.UserId
|
||||
.Returns(userId);
|
||||
|
||||
sutProvider.GetDependency<ICollectionRepository>()
|
||||
.GetByIdAsync(collectionId, userId)
|
||||
.Returns(new CollectionDetails
|
||||
{
|
||||
OrganizationId = orgId,
|
||||
});
|
||||
|
||||
_ = await sutProvider.Sut.Put(orgId, collectionId, collectionRequest);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task Put_CanNotEditAssignedCollection_ThrowsNotFound(Guid orgId, Guid collectionId, Guid userId, CollectionRequestModel collectionRequest,
|
||||
SutProvider<CollectionsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.EditAssignedCollections(orgId)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.UserId
|
||||
.Returns(userId);
|
||||
|
||||
sutProvider.GetDependency<ICollectionRepository>()
|
||||
.GetByIdAsync(collectionId, userId)
|
||||
.Returns(Task.FromResult<CollectionDetails>(null));
|
||||
|
||||
_ = await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.Put(orgId, collectionId, collectionRequest));
|
||||
}
|
||||
_ = await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.Put(orgId, collectionId, collectionRequest));
|
||||
}
|
||||
}
|
||||
|
@ -18,302 +18,301 @@ using Bit.Test.Common.Helpers;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Controllers
|
||||
namespace Bit.Api.Test.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(OrganizationConnectionsController))]
|
||||
[SutProviderCustomize]
|
||||
[JsonDocumentCustomize]
|
||||
public class OrganizationConnectionsControllerTests
|
||||
{
|
||||
[ControllerCustomize(typeof(OrganizationConnectionsController))]
|
||||
[SutProviderCustomize]
|
||||
[JsonDocumentCustomize]
|
||||
public class OrganizationConnectionsControllerTests
|
||||
public static IEnumerable<object[]> ConnectionTypes =>
|
||||
Enum.GetValues<OrganizationConnectionType>().Select(p => new object[] { p });
|
||||
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(true, true)]
|
||||
[BitAutoData(false, true)]
|
||||
[BitAutoData(true, false)]
|
||||
[BitAutoData(false, false)]
|
||||
public void ConnectionEnabled_RequiresBothSelfHostAndCommunications(bool selfHosted, bool enableCloudCommunication, SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
public static IEnumerable<object[]> ConnectionTypes =>
|
||||
Enum.GetValues<OrganizationConnectionType>().Select(p => new object[] { p });
|
||||
var globalSettingsMock = sutProvider.GetDependency<IGlobalSettings>();
|
||||
globalSettingsMock.SelfHosted.Returns(selfHosted);
|
||||
globalSettingsMock.EnableCloudCommunication.Returns(enableCloudCommunication);
|
||||
|
||||
Action<bool> assert = selfHosted && enableCloudCommunication ? Assert.True : Assert.False;
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(true, true)]
|
||||
[BitAutoData(false, true)]
|
||||
[BitAutoData(true, false)]
|
||||
[BitAutoData(false, false)]
|
||||
public void ConnectionEnabled_RequiresBothSelfHostAndCommunications(bool selfHosted, bool enableCloudCommunication, SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
var globalSettingsMock = sutProvider.GetDependency<IGlobalSettings>();
|
||||
globalSettingsMock.SelfHosted.Returns(selfHosted);
|
||||
globalSettingsMock.EnableCloudCommunication.Returns(enableCloudCommunication);
|
||||
var result = sutProvider.Sut.ConnectionsEnabled();
|
||||
|
||||
Action<bool> assert = selfHosted && enableCloudCommunication ? Assert.True : Assert.False;
|
||||
|
||||
var result = sutProvider.Sut.ConnectionsEnabled();
|
||||
|
||||
assert(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CreateConnection_CloudBillingSync_RequiresOwnerPermissions(SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
var model = new OrganizationConnectionRequestModel
|
||||
{
|
||||
Type = OrganizationConnectionType.CloudBillingSync,
|
||||
};
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.CreateConnection(model));
|
||||
|
||||
Assert.Contains($"You do not have permission to create a connection of type", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(ConnectionTypes))]
|
||||
public async Task CreateConnection_OnlyOneConnectionOfEachType(OrganizationConnectionType type,
|
||||
OrganizationConnectionRequestModel model, BillingSyncConfig config, Guid existingEntityId,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
model.Type = type;
|
||||
model.Config = JsonDocumentFromObject(config);
|
||||
var typedModel = new OrganizationConnectionRequestModel<BillingSyncConfig>(model);
|
||||
var existing = typedModel.ToData(existingEntityId).ToEntity();
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.OrganizationId).Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>().GetByOrganizationIdTypeAsync(model.OrganizationId, type).Returns(new[] { existing });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.CreateConnection(model));
|
||||
|
||||
Assert.Contains($"The requested organization already has a connection of type {model.Type}. Only one of each connection type may exist per organization.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CreateConnection_BillingSyncType_InvalidLicense_Throws(OrganizationConnectionRequestModel model,
|
||||
BillingSyncConfig config, Guid cloudOrgId, OrganizationLicense organizationLicense,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
model.Type = OrganizationConnectionType.CloudBillingSync;
|
||||
organizationLicense.Id = cloudOrgId;
|
||||
|
||||
model.Config = JsonDocumentFromObject(config);
|
||||
var typedModel = new OrganizationConnectionRequestModel<BillingSyncConfig>(model);
|
||||
typedModel.ParsedConfig.CloudOrganizationId = cloudOrgId;
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(model.OrganizationId)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<ILicensingService>()
|
||||
.ReadOrganizationLicenseAsync(model.OrganizationId)
|
||||
.Returns(organizationLicense);
|
||||
|
||||
sutProvider.GetDependency<ILicensingService>()
|
||||
.VerifyLicense(organizationLicense)
|
||||
.Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(async () => await sutProvider.Sut.CreateConnection(model));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CreateConnection_Success(OrganizationConnectionRequestModel model, BillingSyncConfig config,
|
||||
Guid cloudOrgId, OrganizationLicense organizationLicense, SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
organizationLicense.Id = cloudOrgId;
|
||||
|
||||
model.Config = JsonDocumentFromObject(config);
|
||||
var typedModel = new OrganizationConnectionRequestModel<BillingSyncConfig>(model);
|
||||
typedModel.ParsedConfig.CloudOrganizationId = cloudOrgId;
|
||||
|
||||
sutProvider.GetDependency<IGlobalSettings>().SelfHosted.Returns(true);
|
||||
sutProvider.GetDependency<ICreateOrganizationConnectionCommand>().CreateAsync<BillingSyncConfig>(default)
|
||||
.ReturnsForAnyArgs(typedModel.ToData(Guid.NewGuid()).ToEntity());
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<ILicensingService>()
|
||||
.ReadOrganizationLicenseAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationLicense);
|
||||
|
||||
sutProvider.GetDependency<ILicensingService>()
|
||||
.VerifyLicense(organizationLicense)
|
||||
.Returns(true);
|
||||
|
||||
await sutProvider.Sut.CreateConnection(model);
|
||||
|
||||
await sutProvider.GetDependency<ICreateOrganizationConnectionCommand>().Received(1)
|
||||
.CreateAsync(Arg.Is(AssertHelper.AssertPropertyEqual(typedModel.ToData())));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateConnection_RequiresOwnerPermissions(SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(new OrganizationConnection());
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateConnection(default, null));
|
||||
|
||||
Assert.Contains("You do not have permission to update this connection.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(OrganizationConnectionType.CloudBillingSync)]
|
||||
public async Task UpdateConnection_BillingSync_OnlyOneConnectionOfEachType(OrganizationConnectionType type,
|
||||
OrganizationConnection existing1, OrganizationConnection existing2, BillingSyncConfig config,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
existing1.Type = existing2.Type = type;
|
||||
existing1.Config = JsonSerializer.Serialize(config);
|
||||
var typedModel = RequestModelFromEntity<BillingSyncConfig>(existing1);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(typedModel.OrganizationId).Returns(true);
|
||||
|
||||
var orgConnectionRepository = sutProvider.GetDependency<IOrganizationConnectionRepository>();
|
||||
orgConnectionRepository.GetByIdAsync(existing1.Id).Returns(existing1);
|
||||
orgConnectionRepository.GetByIdAsync(existing2.Id).Returns(existing2);
|
||||
orgConnectionRepository.GetByOrganizationIdTypeAsync(typedModel.OrganizationId, type).Returns(new[] { existing1, existing2 });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateConnection(existing1.Id, typedModel));
|
||||
|
||||
Assert.Contains($"The requested organization already has a connection of type {typedModel.Type}. Only one of each connection type may exist per organization.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(OrganizationConnectionType.Scim)]
|
||||
public async Task UpdateConnection_Scim_OnlyOneConnectionOfEachType(OrganizationConnectionType type,
|
||||
OrganizationConnection existing1, OrganizationConnection existing2, ScimConfig config,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
existing1.Type = existing2.Type = type;
|
||||
existing1.Config = JsonSerializer.Serialize(config);
|
||||
var typedModel = RequestModelFromEntity<ScimConfig>(existing1);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(typedModel.OrganizationId).Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>()
|
||||
.GetByIdAsync(existing1.Id)
|
||||
.Returns(existing1);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageScim(typedModel.OrganizationId).Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>()
|
||||
.GetByOrganizationIdTypeAsync(typedModel.OrganizationId, type)
|
||||
.Returns(new[] { existing1, existing2 });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateConnection(existing1.Id, typedModel));
|
||||
|
||||
Assert.Contains($"The requested organization already has a connection of type {typedModel.Type}. Only one of each connection type may exist per organization.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateConnection_Success(OrganizationConnection existing, BillingSyncConfig config,
|
||||
OrganizationConnection updated,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
existing.SetConfig(new BillingSyncConfig
|
||||
{
|
||||
CloudOrganizationId = config.CloudOrganizationId,
|
||||
});
|
||||
updated.Config = JsonSerializer.Serialize(config);
|
||||
updated.Id = existing.Id;
|
||||
updated.Type = OrganizationConnectionType.CloudBillingSync;
|
||||
var model = RequestModelFromEntity<BillingSyncConfig>(updated);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>()
|
||||
.GetByOrganizationIdTypeAsync(model.OrganizationId, model.Type)
|
||||
.Returns(new[] { existing });
|
||||
sutProvider.GetDependency<IUpdateOrganizationConnectionCommand>()
|
||||
.UpdateAsync<BillingSyncConfig>(default)
|
||||
.ReturnsForAnyArgs(updated);
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>()
|
||||
.GetByIdAsync(existing.Id)
|
||||
.Returns(existing);
|
||||
|
||||
var expected = new OrganizationConnectionResponseModel(updated, typeof(BillingSyncConfig));
|
||||
var result = await sutProvider.Sut.UpdateConnection(existing.Id, model);
|
||||
|
||||
AssertHelper.AssertPropertyEqual(expected, result);
|
||||
await sutProvider.GetDependency<IUpdateOrganizationConnectionCommand>().Received(1)
|
||||
.UpdateAsync(Arg.Is(AssertHelper.AssertPropertyEqual(model.ToData(updated.Id))));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateConnection_DoesNotExist_ThrowsNotFound(SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.UpdateConnection(Guid.NewGuid(), null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetConnection_RequiresOwnerPermissions(Guid connectionId, SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.GetConnection(connectionId, OrganizationConnectionType.CloudBillingSync));
|
||||
|
||||
Assert.Contains("You do not have permission to retrieve a connection of type", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetConnection_Success(OrganizationConnection connection, BillingSyncConfig config,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
connection.Config = JsonSerializer.Serialize(config);
|
||||
|
||||
sutProvider.GetDependency<IGlobalSettings>().SelfHosted.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>()
|
||||
.GetByOrganizationIdTypeAsync(connection.OrganizationId, connection.Type)
|
||||
.Returns(new[] { connection });
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(connection.OrganizationId).Returns(true);
|
||||
|
||||
var expected = new OrganizationConnectionResponseModel(connection, typeof(BillingSyncConfig));
|
||||
var actual = await sutProvider.Sut.GetConnection(connection.OrganizationId, connection.Type);
|
||||
|
||||
AssertHelper.AssertPropertyEqual(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task DeleteConnection_NotFound(Guid connectionId,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.DeleteConnection(connectionId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task DeleteConnection_RequiresOwnerPermissions(OrganizationConnection connection,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>().GetByIdAsync(connection.Id).Returns(connection);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.DeleteConnection(connection.Id));
|
||||
|
||||
Assert.Contains("You do not have permission to remove this connection of type", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task DeleteConnection_Success(OrganizationConnection connection,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>().GetByIdAsync(connection.Id).Returns(connection);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(connection.OrganizationId).Returns(true);
|
||||
|
||||
await sutProvider.Sut.DeleteConnection(connection.Id);
|
||||
|
||||
await sutProvider.GetDependency<IDeleteOrganizationConnectionCommand>().DeleteAsync(connection);
|
||||
}
|
||||
|
||||
private static OrganizationConnectionRequestModel<T> RequestModelFromEntity<T>(OrganizationConnection entity)
|
||||
where T : new()
|
||||
{
|
||||
return new(new OrganizationConnectionRequestModel()
|
||||
{
|
||||
Type = entity.Type,
|
||||
OrganizationId = entity.OrganizationId,
|
||||
Enabled = entity.Enabled,
|
||||
Config = JsonDocument.Parse(entity.Config),
|
||||
});
|
||||
}
|
||||
|
||||
private static JsonDocument JsonDocumentFromObject<T>(T obj) => JsonDocument.Parse(JsonSerializer.Serialize(obj));
|
||||
assert(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CreateConnection_CloudBillingSync_RequiresOwnerPermissions(SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
var model = new OrganizationConnectionRequestModel
|
||||
{
|
||||
Type = OrganizationConnectionType.CloudBillingSync,
|
||||
};
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.CreateConnection(model));
|
||||
|
||||
Assert.Contains($"You do not have permission to create a connection of type", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(ConnectionTypes))]
|
||||
public async Task CreateConnection_OnlyOneConnectionOfEachType(OrganizationConnectionType type,
|
||||
OrganizationConnectionRequestModel model, BillingSyncConfig config, Guid existingEntityId,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
model.Type = type;
|
||||
model.Config = JsonDocumentFromObject(config);
|
||||
var typedModel = new OrganizationConnectionRequestModel<BillingSyncConfig>(model);
|
||||
var existing = typedModel.ToData(existingEntityId).ToEntity();
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.OrganizationId).Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>().GetByOrganizationIdTypeAsync(model.OrganizationId, type).Returns(new[] { existing });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.CreateConnection(model));
|
||||
|
||||
Assert.Contains($"The requested organization already has a connection of type {model.Type}. Only one of each connection type may exist per organization.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CreateConnection_BillingSyncType_InvalidLicense_Throws(OrganizationConnectionRequestModel model,
|
||||
BillingSyncConfig config, Guid cloudOrgId, OrganizationLicense organizationLicense,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
model.Type = OrganizationConnectionType.CloudBillingSync;
|
||||
organizationLicense.Id = cloudOrgId;
|
||||
|
||||
model.Config = JsonDocumentFromObject(config);
|
||||
var typedModel = new OrganizationConnectionRequestModel<BillingSyncConfig>(model);
|
||||
typedModel.ParsedConfig.CloudOrganizationId = cloudOrgId;
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(model.OrganizationId)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<ILicensingService>()
|
||||
.ReadOrganizationLicenseAsync(model.OrganizationId)
|
||||
.Returns(organizationLicense);
|
||||
|
||||
sutProvider.GetDependency<ILicensingService>()
|
||||
.VerifyLicense(organizationLicense)
|
||||
.Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(async () => await sutProvider.Sut.CreateConnection(model));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CreateConnection_Success(OrganizationConnectionRequestModel model, BillingSyncConfig config,
|
||||
Guid cloudOrgId, OrganizationLicense organizationLicense, SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
organizationLicense.Id = cloudOrgId;
|
||||
|
||||
model.Config = JsonDocumentFromObject(config);
|
||||
var typedModel = new OrganizationConnectionRequestModel<BillingSyncConfig>(model);
|
||||
typedModel.ParsedConfig.CloudOrganizationId = cloudOrgId;
|
||||
|
||||
sutProvider.GetDependency<IGlobalSettings>().SelfHosted.Returns(true);
|
||||
sutProvider.GetDependency<ICreateOrganizationConnectionCommand>().CreateAsync<BillingSyncConfig>(default)
|
||||
.ReturnsForAnyArgs(typedModel.ToData(Guid.NewGuid()).ToEntity());
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<ILicensingService>()
|
||||
.ReadOrganizationLicenseAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationLicense);
|
||||
|
||||
sutProvider.GetDependency<ILicensingService>()
|
||||
.VerifyLicense(organizationLicense)
|
||||
.Returns(true);
|
||||
|
||||
await sutProvider.Sut.CreateConnection(model);
|
||||
|
||||
await sutProvider.GetDependency<ICreateOrganizationConnectionCommand>().Received(1)
|
||||
.CreateAsync(Arg.Is(AssertHelper.AssertPropertyEqual(typedModel.ToData())));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateConnection_RequiresOwnerPermissions(SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(new OrganizationConnection());
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateConnection(default, null));
|
||||
|
||||
Assert.Contains("You do not have permission to update this connection.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(OrganizationConnectionType.CloudBillingSync)]
|
||||
public async Task UpdateConnection_BillingSync_OnlyOneConnectionOfEachType(OrganizationConnectionType type,
|
||||
OrganizationConnection existing1, OrganizationConnection existing2, BillingSyncConfig config,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
existing1.Type = existing2.Type = type;
|
||||
existing1.Config = JsonSerializer.Serialize(config);
|
||||
var typedModel = RequestModelFromEntity<BillingSyncConfig>(existing1);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(typedModel.OrganizationId).Returns(true);
|
||||
|
||||
var orgConnectionRepository = sutProvider.GetDependency<IOrganizationConnectionRepository>();
|
||||
orgConnectionRepository.GetByIdAsync(existing1.Id).Returns(existing1);
|
||||
orgConnectionRepository.GetByIdAsync(existing2.Id).Returns(existing2);
|
||||
orgConnectionRepository.GetByOrganizationIdTypeAsync(typedModel.OrganizationId, type).Returns(new[] { existing1, existing2 });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateConnection(existing1.Id, typedModel));
|
||||
|
||||
Assert.Contains($"The requested organization already has a connection of type {typedModel.Type}. Only one of each connection type may exist per organization.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(OrganizationConnectionType.Scim)]
|
||||
public async Task UpdateConnection_Scim_OnlyOneConnectionOfEachType(OrganizationConnectionType type,
|
||||
OrganizationConnection existing1, OrganizationConnection existing2, ScimConfig config,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
existing1.Type = existing2.Type = type;
|
||||
existing1.Config = JsonSerializer.Serialize(config);
|
||||
var typedModel = RequestModelFromEntity<ScimConfig>(existing1);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(typedModel.OrganizationId).Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>()
|
||||
.GetByIdAsync(existing1.Id)
|
||||
.Returns(existing1);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageScim(typedModel.OrganizationId).Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>()
|
||||
.GetByOrganizationIdTypeAsync(typedModel.OrganizationId, type)
|
||||
.Returns(new[] { existing1, existing2 });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateConnection(existing1.Id, typedModel));
|
||||
|
||||
Assert.Contains($"The requested organization already has a connection of type {typedModel.Type}. Only one of each connection type may exist per organization.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateConnection_Success(OrganizationConnection existing, BillingSyncConfig config,
|
||||
OrganizationConnection updated,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
existing.SetConfig(new BillingSyncConfig
|
||||
{
|
||||
CloudOrganizationId = config.CloudOrganizationId,
|
||||
});
|
||||
updated.Config = JsonSerializer.Serialize(config);
|
||||
updated.Id = existing.Id;
|
||||
updated.Type = OrganizationConnectionType.CloudBillingSync;
|
||||
var model = RequestModelFromEntity<BillingSyncConfig>(updated);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>()
|
||||
.GetByOrganizationIdTypeAsync(model.OrganizationId, model.Type)
|
||||
.Returns(new[] { existing });
|
||||
sutProvider.GetDependency<IUpdateOrganizationConnectionCommand>()
|
||||
.UpdateAsync<BillingSyncConfig>(default)
|
||||
.ReturnsForAnyArgs(updated);
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>()
|
||||
.GetByIdAsync(existing.Id)
|
||||
.Returns(existing);
|
||||
|
||||
var expected = new OrganizationConnectionResponseModel(updated, typeof(BillingSyncConfig));
|
||||
var result = await sutProvider.Sut.UpdateConnection(existing.Id, model);
|
||||
|
||||
AssertHelper.AssertPropertyEqual(expected, result);
|
||||
await sutProvider.GetDependency<IUpdateOrganizationConnectionCommand>().Received(1)
|
||||
.UpdateAsync(Arg.Is(AssertHelper.AssertPropertyEqual(model.ToData(updated.Id))));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateConnection_DoesNotExist_ThrowsNotFound(SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.UpdateConnection(Guid.NewGuid(), null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetConnection_RequiresOwnerPermissions(Guid connectionId, SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.GetConnection(connectionId, OrganizationConnectionType.CloudBillingSync));
|
||||
|
||||
Assert.Contains("You do not have permission to retrieve a connection of type", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetConnection_Success(OrganizationConnection connection, BillingSyncConfig config,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
connection.Config = JsonSerializer.Serialize(config);
|
||||
|
||||
sutProvider.GetDependency<IGlobalSettings>().SelfHosted.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>()
|
||||
.GetByOrganizationIdTypeAsync(connection.OrganizationId, connection.Type)
|
||||
.Returns(new[] { connection });
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(connection.OrganizationId).Returns(true);
|
||||
|
||||
var expected = new OrganizationConnectionResponseModel(connection, typeof(BillingSyncConfig));
|
||||
var actual = await sutProvider.Sut.GetConnection(connection.OrganizationId, connection.Type);
|
||||
|
||||
AssertHelper.AssertPropertyEqual(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task DeleteConnection_NotFound(Guid connectionId,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.DeleteConnection(connectionId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task DeleteConnection_RequiresOwnerPermissions(OrganizationConnection connection,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>().GetByIdAsync(connection.Id).Returns(connection);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.DeleteConnection(connection.Id));
|
||||
|
||||
Assert.Contains("You do not have permission to remove this connection of type", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task DeleteConnection_Success(OrganizationConnection connection,
|
||||
SutProvider<OrganizationConnectionsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>().GetByIdAsync(connection.Id).Returns(connection);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(connection.OrganizationId).Returns(true);
|
||||
|
||||
await sutProvider.Sut.DeleteConnection(connection.Id);
|
||||
|
||||
await sutProvider.GetDependency<IDeleteOrganizationConnectionCommand>().DeleteAsync(connection);
|
||||
}
|
||||
|
||||
private static OrganizationConnectionRequestModel<T> RequestModelFromEntity<T>(OrganizationConnection entity)
|
||||
where T : new()
|
||||
{
|
||||
return new(new OrganizationConnectionRequestModel()
|
||||
{
|
||||
Type = entity.Type,
|
||||
OrganizationId = entity.OrganizationId,
|
||||
Enabled = entity.Enabled,
|
||||
Config = JsonDocument.Parse(entity.Config),
|
||||
});
|
||||
}
|
||||
|
||||
private static JsonDocument JsonDocumentFromObject<T>(T obj) => JsonDocument.Parse(JsonSerializer.Serialize(obj));
|
||||
}
|
||||
|
@ -13,136 +13,135 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Controllers
|
||||
namespace Bit.Api.Test.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(OrganizationSponsorshipsController))]
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationSponsorshipsControllerTests
|
||||
{
|
||||
[ControllerCustomize(typeof(OrganizationSponsorshipsController))]
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationSponsorshipsControllerTests
|
||||
public static IEnumerable<object[]> EnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product == ProductType.Enterprise).Select(p => new object[] { p });
|
||||
public static IEnumerable<object[]> NonEnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product != ProductType.Enterprise).Select(p => new object[] { p });
|
||||
public static IEnumerable<object[]> NonFamiliesPlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product != ProductType.Families).Select(p => new object[] { p });
|
||||
|
||||
public static IEnumerable<object[]> NonConfirmedOrganizationUsersStatuses =>
|
||||
Enum.GetValues<OrganizationUserStatusType>()
|
||||
.Where(s => s != OrganizationUserStatusType.Confirmed)
|
||||
.Select(s => new object[] { s });
|
||||
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RedeemSponsorship_BadToken_ThrowsBadRequest(string sponsorshipToken, User user,
|
||||
OrganizationSponsorshipRedeemRequestModel model, SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||
{
|
||||
public static IEnumerable<object[]> EnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product == ProductType.Enterprise).Select(p => new object[] { p });
|
||||
public static IEnumerable<object[]> NonEnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product != ProductType.Enterprise).Select(p => new object[] { p });
|
||||
public static IEnumerable<object[]> NonFamiliesPlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product != ProductType.Families).Select(p => new object[] { p });
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(user.Id);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
||||
.Returns(user);
|
||||
sutProvider.GetDependency<IValidateRedemptionTokenCommand>().ValidateRedemptionTokenAsync(sponsorshipToken,
|
||||
user.Email).Returns((false, null));
|
||||
|
||||
public static IEnumerable<object[]> NonConfirmedOrganizationUsersStatuses =>
|
||||
Enum.GetValues<OrganizationUserStatusType>()
|
||||
.Where(s => s != OrganizationUserStatusType.Confirmed)
|
||||
.Select(s => new object[] { s });
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RedeemSponsorship(sponsorshipToken, model));
|
||||
|
||||
Assert.Contains("Failed to parse sponsorship token.", exception.Message);
|
||||
await sutProvider.GetDependency<ISetUpSponsorshipCommand>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SetUpSponsorshipAsync(default, default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RedeemSponsorship_BadToken_ThrowsBadRequest(string sponsorshipToken, User user,
|
||||
OrganizationSponsorshipRedeemRequestModel model, SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(user.Id);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
||||
.Returns(user);
|
||||
sutProvider.GetDependency<IValidateRedemptionTokenCommand>().ValidateRedemptionTokenAsync(sponsorshipToken,
|
||||
user.Email).Returns((false, null));
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RedeemSponsorship_NotSponsoredOrgOwner_ThrowsBadRequest(string sponsorshipToken, User user,
|
||||
OrganizationSponsorship sponsorship, OrganizationSponsorshipRedeemRequestModel model,
|
||||
SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(user.Id);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
||||
.Returns(user);
|
||||
sutProvider.GetDependency<IValidateRedemptionTokenCommand>().ValidateRedemptionTokenAsync(sponsorshipToken,
|
||||
user.Email).Returns((true, sponsorship));
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.SponsoredOrganizationId).Returns(false);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RedeemSponsorship(sponsorshipToken, model));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RedeemSponsorship(sponsorshipToken, model));
|
||||
|
||||
Assert.Contains("Failed to parse sponsorship token.", exception.Message);
|
||||
await sutProvider.GetDependency<ISetUpSponsorshipCommand>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SetUpSponsorshipAsync(default, default);
|
||||
}
|
||||
Assert.Contains("Can only redeem sponsorship for an organization you own.", exception.Message);
|
||||
await sutProvider.GetDependency<ISetUpSponsorshipCommand>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SetUpSponsorshipAsync(default, default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RedeemSponsorship_NotSponsoredOrgOwner_ThrowsBadRequest(string sponsorshipToken, User user,
|
||||
OrganizationSponsorship sponsorship, OrganizationSponsorshipRedeemRequestModel model,
|
||||
SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(user.Id);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
||||
.Returns(user);
|
||||
sutProvider.GetDependency<IValidateRedemptionTokenCommand>().ValidateRedemptionTokenAsync(sponsorshipToken,
|
||||
user.Email).Returns((true, sponsorship));
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.SponsoredOrganizationId).Returns(false);
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RedeemSponsorship_NotSponsoredOrgOwner_Success(string sponsorshipToken, User user,
|
||||
OrganizationSponsorship sponsorship, Organization sponsoringOrganization,
|
||||
OrganizationSponsorshipRedeemRequestModel model, SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(user.Id);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
||||
.Returns(user);
|
||||
sutProvider.GetDependency<IValidateRedemptionTokenCommand>().ValidateRedemptionTokenAsync(sponsorshipToken,
|
||||
user.Email).Returns((true, sponsorship));
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.SponsoredOrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(model.SponsoredOrganizationId).Returns(sponsoringOrganization);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RedeemSponsorship(sponsorshipToken, model));
|
||||
await sutProvider.Sut.RedeemSponsorship(sponsorshipToken, model);
|
||||
|
||||
Assert.Contains("Can only redeem sponsorship for an organization you own.", exception.Message);
|
||||
await sutProvider.GetDependency<ISetUpSponsorshipCommand>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SetUpSponsorshipAsync(default, default);
|
||||
}
|
||||
await sutProvider.GetDependency<ISetUpSponsorshipCommand>().Received(1)
|
||||
.SetUpSponsorshipAsync(sponsorship, sponsoringOrganization);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RedeemSponsorship_NotSponsoredOrgOwner_Success(string sponsorshipToken, User user,
|
||||
OrganizationSponsorship sponsorship, Organization sponsoringOrganization,
|
||||
OrganizationSponsorshipRedeemRequestModel model, SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(user.Id);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
||||
.Returns(user);
|
||||
sutProvider.GetDependency<IValidateRedemptionTokenCommand>().ValidateRedemptionTokenAsync(sponsorshipToken,
|
||||
user.Email).Returns((true, sponsorship));
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.SponsoredOrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(model.SponsoredOrganizationId).Returns(sponsoringOrganization);
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PreValidateSponsorshipToken_ValidatesToken_Success(string sponsorshipToken, User user,
|
||||
OrganizationSponsorship sponsorship, SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(user.Id);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
||||
.Returns(user);
|
||||
sutProvider.GetDependency<IValidateRedemptionTokenCommand>()
|
||||
.ValidateRedemptionTokenAsync(sponsorshipToken, user.Email).Returns((true, sponsorship));
|
||||
|
||||
await sutProvider.Sut.RedeemSponsorship(sponsorshipToken, model);
|
||||
await sutProvider.Sut.PreValidateSponsorshipToken(sponsorshipToken);
|
||||
|
||||
await sutProvider.GetDependency<ISetUpSponsorshipCommand>().Received(1)
|
||||
.SetUpSponsorshipAsync(sponsorship, sponsoringOrganization);
|
||||
}
|
||||
await sutProvider.GetDependency<IValidateRedemptionTokenCommand>().Received(1)
|
||||
.ValidateRedemptionTokenAsync(sponsorshipToken, user.Email);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PreValidateSponsorshipToken_ValidatesToken_Success(string sponsorshipToken, User user,
|
||||
OrganizationSponsorship sponsorship, SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(user.Id);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
||||
.Returns(user);
|
||||
sutProvider.GetDependency<IValidateRedemptionTokenCommand>()
|
||||
.ValidateRedemptionTokenAsync(sponsorshipToken, user.Email).Returns((true, sponsorship));
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_WrongSponsoringUser_ThrowsBadRequest(OrganizationUser sponsoringOrgUser,
|
||||
Guid currentUserId, SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(currentUserId);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(sponsoringOrgUser.Id)
|
||||
.Returns(sponsoringOrgUser);
|
||||
|
||||
await sutProvider.Sut.PreValidateSponsorshipToken(sponsorshipToken);
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RevokeSponsorship(sponsoringOrgUser.Id));
|
||||
|
||||
await sutProvider.GetDependency<IValidateRedemptionTokenCommand>().Received(1)
|
||||
.ValidateRedemptionTokenAsync(sponsorshipToken, user.Email);
|
||||
}
|
||||
Assert.Contains("Can only revoke a sponsorship you granted.", exception.Message);
|
||||
await sutProvider.GetDependency<IRemoveSponsorshipCommand>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.RemoveSponsorshipAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_WrongSponsoringUser_ThrowsBadRequest(OrganizationUser sponsoringOrgUser,
|
||||
Guid currentUserId, SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(currentUserId);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(sponsoringOrgUser.Id)
|
||||
.Returns(sponsoringOrgUser);
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RemoveSponsorship_WrongOrgUserType_ThrowsBadRequest(Organization sponsoredOrg,
|
||||
SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(Arg.Any<Guid>()).Returns(false);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RevokeSponsorship(sponsoringOrgUser.Id));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RemoveSponsorship(sponsoredOrg.Id));
|
||||
|
||||
Assert.Contains("Can only revoke a sponsorship you granted.", exception.Message);
|
||||
await sutProvider.GetDependency<IRemoveSponsorshipCommand>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.RemoveSponsorshipAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RemoveSponsorship_WrongOrgUserType_ThrowsBadRequest(Organization sponsoredOrg,
|
||||
SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(Arg.Any<Guid>()).Returns(false);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RemoveSponsorship(sponsoredOrg.Id));
|
||||
|
||||
Assert.Contains("Only the owner of an organization can remove sponsorship.", exception.Message);
|
||||
await sutProvider.GetDependency<IRemoveSponsorshipCommand>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.RemoveSponsorshipAsync(default);
|
||||
}
|
||||
Assert.Contains("Only the owner of an organization can remove sponsorship.", exception.Message);
|
||||
await sutProvider.GetDependency<IRemoveSponsorshipCommand>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.RemoveSponsorshipAsync(default);
|
||||
}
|
||||
}
|
||||
|
@ -10,57 +10,56 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Controllers
|
||||
namespace Bit.Api.Test.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(OrganizationUsersController))]
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationUsersControllerTests
|
||||
{
|
||||
[ControllerCustomize(typeof(OrganizationUsersController))]
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationUsersControllerTests
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Accept_RequiresKnownUser(Guid orgId, Guid orgUserId, OrganizationUserAcceptRequestModel model,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Accept_RequiresKnownUser(Guid orgId, Guid orgUserId, OrganizationUserAcceptRequestModel model,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(default).ReturnsForAnyArgs((User)null);
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(() => sutProvider.Sut.Accept(orgId, orgUserId, model));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Accept_NoMasterPasswordReset(Guid orgId, Guid orgUserId,
|
||||
OrganizationUserAcceptRequestModel model, User user, SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(default).ReturnsForAnyArgs(user);
|
||||
|
||||
await sutProvider.Sut.Accept(orgId, orgUserId, model);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationService>().Received(1)
|
||||
.AcceptUserAsync(orgUserId, user, model.Token, sutProvider.GetDependency<IUserService>());
|
||||
await sutProvider.GetDependency<IOrganizationService>().DidNotReceiveWithAnyArgs()
|
||||
.UpdateUserResetPasswordEnrollmentAsync(default, default, default, default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Accept_RequireMasterPasswordReset(Guid orgId, Guid orgUserId,
|
||||
OrganizationUserAcceptRequestModel model, User user, SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
var policy = new Policy
|
||||
{
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(default).ReturnsForAnyArgs((User)null);
|
||||
Enabled = true,
|
||||
Data = CoreHelpers.ClassToJsonData(new ResetPasswordDataModel { AutoEnrollEnabled = true, }),
|
||||
};
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(default).ReturnsForAnyArgs(user);
|
||||
sutProvider.GetDependency<IPolicyRepository>().GetByOrganizationIdTypeAsync(orgId,
|
||||
Core.Enums.PolicyType.ResetPassword).Returns(policy);
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(() => sutProvider.Sut.Accept(orgId, orgUserId, model));
|
||||
}
|
||||
await sutProvider.Sut.Accept(orgId, orgUserId, model);
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Accept_NoMasterPasswordReset(Guid orgId, Guid orgUserId,
|
||||
OrganizationUserAcceptRequestModel model, User user, SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(default).ReturnsForAnyArgs(user);
|
||||
|
||||
await sutProvider.Sut.Accept(orgId, orgUserId, model);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationService>().Received(1)
|
||||
.AcceptUserAsync(orgUserId, user, model.Token, sutProvider.GetDependency<IUserService>());
|
||||
await sutProvider.GetDependency<IOrganizationService>().DidNotReceiveWithAnyArgs()
|
||||
.UpdateUserResetPasswordEnrollmentAsync(default, default, default, default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Accept_RequireMasterPasswordReset(Guid orgId, Guid orgUserId,
|
||||
OrganizationUserAcceptRequestModel model, User user, SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
var policy = new Policy
|
||||
{
|
||||
Enabled = true,
|
||||
Data = CoreHelpers.ClassToJsonData(new ResetPasswordDataModel { AutoEnrollEnabled = true, }),
|
||||
};
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(default).ReturnsForAnyArgs(user);
|
||||
sutProvider.GetDependency<IPolicyRepository>().GetByOrganizationIdTypeAsync(orgId,
|
||||
Core.Enums.PolicyType.ResetPassword).Returns(policy);
|
||||
|
||||
await sutProvider.Sut.Accept(orgId, orgUserId, model);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationService>().Received(1)
|
||||
.AcceptUserAsync(orgUserId, user, model.Token, sutProvider.GetDependency<IUserService>());
|
||||
await sutProvider.GetDependency<IOrganizationService>().Received(1)
|
||||
.UpdateUserResetPasswordEnrollmentAsync(orgId, user.Id, model.ResetPasswordKey, user.Id);
|
||||
}
|
||||
await sutProvider.GetDependency<IOrganizationService>().Received(1)
|
||||
.AcceptUserAsync(orgUserId, user, model.Token, sutProvider.GetDependency<IUserService>());
|
||||
await sutProvider.GetDependency<IOrganizationService>().Received(1)
|
||||
.UpdateUserResetPasswordEnrollmentAsync(orgId, user.Id, model.ResetPasswordKey, user.Id);
|
||||
}
|
||||
}
|
||||
|
@ -12,109 +12,108 @@ using Bit.Core.Settings;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Controllers
|
||||
namespace Bit.Api.Test.Controllers;
|
||||
|
||||
public class OrganizationsControllerTests : IDisposable
|
||||
{
|
||||
public class OrganizationsControllerTests : IDisposable
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IOrganizationService _organizationService;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IPaymentService _paymentService;
|
||||
private readonly IPolicyRepository _policyRepository;
|
||||
private readonly ISsoConfigRepository _ssoConfigRepository;
|
||||
private readonly ISsoConfigService _ssoConfigService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IGetOrganizationApiKeyCommand _getOrganizationApiKeyCommand;
|
||||
private readonly IRotateOrganizationApiKeyCommand _rotateOrganizationApiKeyCommand;
|
||||
private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository;
|
||||
|
||||
private readonly OrganizationsController _sut;
|
||||
|
||||
public OrganizationsControllerTests()
|
||||
{
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IOrganizationService _organizationService;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IPaymentService _paymentService;
|
||||
private readonly IPolicyRepository _policyRepository;
|
||||
private readonly ISsoConfigRepository _ssoConfigRepository;
|
||||
private readonly ISsoConfigService _ssoConfigService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IGetOrganizationApiKeyCommand _getOrganizationApiKeyCommand;
|
||||
private readonly IRotateOrganizationApiKeyCommand _rotateOrganizationApiKeyCommand;
|
||||
private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository;
|
||||
_currentContext = Substitute.For<ICurrentContext>();
|
||||
_globalSettings = Substitute.For<GlobalSettings>();
|
||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
_organizationService = Substitute.For<IOrganizationService>();
|
||||
_organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
|
||||
_paymentService = Substitute.For<IPaymentService>();
|
||||
_policyRepository = Substitute.For<IPolicyRepository>();
|
||||
_ssoConfigRepository = Substitute.For<ISsoConfigRepository>();
|
||||
_ssoConfigService = Substitute.For<ISsoConfigService>();
|
||||
_getOrganizationApiKeyCommand = Substitute.For<IGetOrganizationApiKeyCommand>();
|
||||
_rotateOrganizationApiKeyCommand = Substitute.For<IRotateOrganizationApiKeyCommand>();
|
||||
_organizationApiKeyRepository = Substitute.For<IOrganizationApiKeyRepository>();
|
||||
_userService = Substitute.For<IUserService>();
|
||||
|
||||
private readonly OrganizationsController _sut;
|
||||
_sut = new OrganizationsController(_organizationRepository, _organizationUserRepository,
|
||||
_policyRepository, _organizationService, _userService, _paymentService, _currentContext,
|
||||
_ssoConfigRepository, _ssoConfigService, _getOrganizationApiKeyCommand, _rotateOrganizationApiKeyCommand,
|
||||
_organizationApiKeyRepository, _globalSettings);
|
||||
}
|
||||
|
||||
public OrganizationsControllerTests()
|
||||
public void Dispose()
|
||||
{
|
||||
_sut?.Dispose();
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task OrganizationsController_UserCannotLeaveOrganizationThatProvidesKeyConnector(
|
||||
Guid orgId, User user)
|
||||
{
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
_currentContext = Substitute.For<ICurrentContext>();
|
||||
_globalSettings = Substitute.For<GlobalSettings>();
|
||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
_organizationService = Substitute.For<IOrganizationService>();
|
||||
_organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
|
||||
_paymentService = Substitute.For<IPaymentService>();
|
||||
_policyRepository = Substitute.For<IPolicyRepository>();
|
||||
_ssoConfigRepository = Substitute.For<ISsoConfigRepository>();
|
||||
_ssoConfigService = Substitute.For<ISsoConfigService>();
|
||||
_getOrganizationApiKeyCommand = Substitute.For<IGetOrganizationApiKeyCommand>();
|
||||
_rotateOrganizationApiKeyCommand = Substitute.For<IRotateOrganizationApiKeyCommand>();
|
||||
_organizationApiKeyRepository = Substitute.For<IOrganizationApiKeyRepository>();
|
||||
_userService = Substitute.For<IUserService>();
|
||||
|
||||
_sut = new OrganizationsController(_organizationRepository, _organizationUserRepository,
|
||||
_policyRepository, _organizationService, _userService, _paymentService, _currentContext,
|
||||
_ssoConfigRepository, _ssoConfigService, _getOrganizationApiKeyCommand, _rotateOrganizationApiKeyCommand,
|
||||
_organizationApiKeyRepository, _globalSettings);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_sut?.Dispose();
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task OrganizationsController_UserCannotLeaveOrganizationThatProvidesKeyConnector(
|
||||
Guid orgId, User user)
|
||||
{
|
||||
var ssoConfig = new SsoConfig
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = orgId,
|
||||
};
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = orgId,
|
||||
};
|
||||
|
||||
user.UsesKeyConnector = true;
|
||||
user.UsesKeyConnector = true;
|
||||
|
||||
_currentContext.OrganizationUser(orgId).Returns(true);
|
||||
_ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(ssoConfig);
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
_currentContext.OrganizationUser(orgId).Returns(true);
|
||||
_ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(ssoConfig);
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.Leave(orgId.ToString()));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => _sut.Leave(orgId.ToString()));
|
||||
|
||||
Assert.Contains("Your organization's Single Sign-On settings prevent you from leaving.",
|
||||
exception.Message);
|
||||
Assert.Contains("Your organization's Single Sign-On settings prevent you from leaving.",
|
||||
exception.Message);
|
||||
|
||||
await _organizationService.DidNotReceiveWithAnyArgs().DeleteUserAsync(default, default);
|
||||
}
|
||||
await _organizationService.DidNotReceiveWithAnyArgs().DeleteUserAsync(default, default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineAutoData(true, false)]
|
||||
[InlineAutoData(false, true)]
|
||||
[InlineAutoData(false, false)]
|
||||
public async Task OrganizationsController_UserCanLeaveOrganizationThatDoesntProvideKeyConnector(
|
||||
bool keyConnectorEnabled, bool userUsesKeyConnector, Guid orgId, User user)
|
||||
[Theory]
|
||||
[InlineAutoData(true, false)]
|
||||
[InlineAutoData(false, true)]
|
||||
[InlineAutoData(false, false)]
|
||||
public async Task OrganizationsController_UserCanLeaveOrganizationThatDoesntProvideKeyConnector(
|
||||
bool keyConnectorEnabled, bool userUsesKeyConnector, Guid orgId, User user)
|
||||
{
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
var ssoConfig = new SsoConfig
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = keyConnectorEnabled,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = orgId,
|
||||
};
|
||||
KeyConnectorEnabled = keyConnectorEnabled,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = orgId,
|
||||
};
|
||||
|
||||
user.UsesKeyConnector = userUsesKeyConnector;
|
||||
user.UsesKeyConnector = userUsesKeyConnector;
|
||||
|
||||
_currentContext.OrganizationUser(orgId).Returns(true);
|
||||
_ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(ssoConfig);
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
_currentContext.OrganizationUser(orgId).Returns(true);
|
||||
_ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(ssoConfig);
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
|
||||
await _organizationService.DeleteUserAsync(orgId, user.Id);
|
||||
await _organizationService.Received(1).DeleteUserAsync(orgId, user.Id);
|
||||
}
|
||||
await _organizationService.DeleteUserAsync(orgId, user.Id);
|
||||
await _organizationService.Received(1).DeleteUserAsync(orgId, user.Id);
|
||||
}
|
||||
}
|
||||
|
@ -15,66 +15,65 @@ using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Controllers
|
||||
namespace Bit.Api.Test.Controllers;
|
||||
|
||||
public class SendsControllerTests : IDisposable
|
||||
{
|
||||
public class SendsControllerTests : IDisposable
|
||||
|
||||
private readonly SendsController _sut;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IUserService _userService;
|
||||
private readonly ISendRepository _sendRepository;
|
||||
private readonly ISendService _sendService;
|
||||
private readonly ISendFileStorageService _sendFileStorageService;
|
||||
private readonly ILogger<SendsController> _logger;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
|
||||
public SendsControllerTests()
|
||||
{
|
||||
_userService = Substitute.For<IUserService>();
|
||||
_sendRepository = Substitute.For<ISendRepository>();
|
||||
_sendService = Substitute.For<ISendService>();
|
||||
_sendFileStorageService = Substitute.For<ISendFileStorageService>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
_logger = Substitute.For<ILogger<SendsController>>();
|
||||
_currentContext = Substitute.For<ICurrentContext>();
|
||||
|
||||
private readonly SendsController _sut;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IUserService _userService;
|
||||
private readonly ISendRepository _sendRepository;
|
||||
private readonly ISendService _sendService;
|
||||
private readonly ISendFileStorageService _sendFileStorageService;
|
||||
private readonly ILogger<SendsController> _logger;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
_sut = new SendsController(
|
||||
_sendRepository,
|
||||
_userService,
|
||||
_sendService,
|
||||
_sendFileStorageService,
|
||||
_logger,
|
||||
_globalSettings,
|
||||
_currentContext
|
||||
);
|
||||
}
|
||||
|
||||
public SendsControllerTests()
|
||||
{
|
||||
_userService = Substitute.For<IUserService>();
|
||||
_sendRepository = Substitute.For<ISendRepository>();
|
||||
_sendService = Substitute.For<ISendService>();
|
||||
_sendFileStorageService = Substitute.For<ISendFileStorageService>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
_logger = Substitute.For<ILogger<SendsController>>();
|
||||
_currentContext = Substitute.For<ICurrentContext>();
|
||||
public void Dispose()
|
||||
{
|
||||
_sut?.Dispose();
|
||||
}
|
||||
|
||||
_sut = new SendsController(
|
||||
_sendRepository,
|
||||
_userService,
|
||||
_sendService,
|
||||
_sendFileStorageService,
|
||||
_logger,
|
||||
_globalSettings,
|
||||
_currentContext
|
||||
);
|
||||
}
|
||||
[Theory, AutoData]
|
||||
public async Task SendsController_WhenSendHidesEmail_CreatorIdentifierShouldBeNull(
|
||||
Guid id, Send send, User user)
|
||||
{
|
||||
var accessId = CoreHelpers.Base64UrlEncode(id.ToByteArray());
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_sut?.Dispose();
|
||||
}
|
||||
send.Id = default;
|
||||
send.Type = SendType.Text;
|
||||
send.Data = JsonSerializer.Serialize(new Dictionary<string, string>());
|
||||
send.HideEmail = true;
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task SendsController_WhenSendHidesEmail_CreatorIdentifierShouldBeNull(
|
||||
Guid id, Send send, User user)
|
||||
{
|
||||
var accessId = CoreHelpers.Base64UrlEncode(id.ToByteArray());
|
||||
_sendService.AccessAsync(id, null).Returns((send, false, false));
|
||||
_userService.GetUserByIdAsync(Arg.Any<Guid>()).Returns(user);
|
||||
|
||||
send.Id = default;
|
||||
send.Type = SendType.Text;
|
||||
send.Data = JsonSerializer.Serialize(new Dictionary<string, string>());
|
||||
send.HideEmail = true;
|
||||
var request = new SendAccessRequestModel();
|
||||
var actionResult = await _sut.Access(accessId, request);
|
||||
var response = (actionResult as ObjectResult)?.Value as SendAccessResponseModel;
|
||||
|
||||
_sendService.AccessAsync(id, null).Returns((send, false, false));
|
||||
_userService.GetUserByIdAsync(Arg.Any<Guid>()).Returns(user);
|
||||
|
||||
var request = new SendAccessRequestModel();
|
||||
var actionResult = await _sut.Access(accessId, request);
|
||||
var response = (actionResult as ObjectResult)?.Value as SendAccessResponseModel;
|
||||
|
||||
Assert.NotNull(response);
|
||||
Assert.Null(response.CreatorIdentifier);
|
||||
}
|
||||
Assert.NotNull(response);
|
||||
Assert.Null(response.CreatorIdentifier);
|
||||
}
|
||||
}
|
||||
|
@ -3,63 +3,62 @@ using Bit.Core.Settings;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Models.Request.Accounts
|
||||
namespace Bit.Api.Test.Models.Request.Accounts;
|
||||
|
||||
public class PremiumRequestModelTests
|
||||
{
|
||||
public class PremiumRequestModelTests
|
||||
public static IEnumerable<object[]> GetValidateData()
|
||||
{
|
||||
public static IEnumerable<object[]> GetValidateData()
|
||||
{
|
||||
// 1. selfHosted
|
||||
// 2. formFile
|
||||
// 3. country
|
||||
// 4. expected
|
||||
// 1. selfHosted
|
||||
// 2. formFile
|
||||
// 3. country
|
||||
// 4. expected
|
||||
|
||||
yield return new object[] { true, null, null, false };
|
||||
yield return new object[] { true, null, "US", false };
|
||||
yield return new object[] { true, new NotImplementedFormFile(), null, false };
|
||||
yield return new object[] { true, new NotImplementedFormFile(), "US", false };
|
||||
yield return new object[] { true, null, null, false };
|
||||
yield return new object[] { true, null, "US", false };
|
||||
yield return new object[] { true, new NotImplementedFormFile(), null, false };
|
||||
yield return new object[] { true, new NotImplementedFormFile(), "US", false };
|
||||
|
||||
yield return new object[] { false, null, null, false };
|
||||
yield return new object[] { false, null, "US", true }; // Only true, cloud with null license AND a Country
|
||||
yield return new object[] { false, new NotImplementedFormFile(), null, false };
|
||||
yield return new object[] { false, new NotImplementedFormFile(), "US", false };
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(GetValidateData))]
|
||||
public void Validate_Success(bool selfHosted, IFormFile formFile, string country, bool expected)
|
||||
{
|
||||
var gs = new GlobalSettings
|
||||
{
|
||||
SelfHosted = selfHosted
|
||||
};
|
||||
|
||||
var sut = new PremiumRequestModel
|
||||
{
|
||||
License = formFile,
|
||||
Country = country,
|
||||
};
|
||||
|
||||
Assert.Equal(expected, sut.Validate(gs));
|
||||
}
|
||||
yield return new object[] { false, null, null, false };
|
||||
yield return new object[] { false, null, "US", true }; // Only true, cloud with null license AND a Country
|
||||
yield return new object[] { false, new NotImplementedFormFile(), null, false };
|
||||
yield return new object[] { false, new NotImplementedFormFile(), "US", false };
|
||||
}
|
||||
|
||||
public class NotImplementedFormFile : IFormFile
|
||||
[Theory]
|
||||
[MemberData(nameof(GetValidateData))]
|
||||
public void Validate_Success(bool selfHosted, IFormFile formFile, string country, bool expected)
|
||||
{
|
||||
public string ContentType => throw new NotImplementedException();
|
||||
var gs = new GlobalSettings
|
||||
{
|
||||
SelfHosted = selfHosted
|
||||
};
|
||||
|
||||
public string ContentDisposition => throw new NotImplementedException();
|
||||
var sut = new PremiumRequestModel
|
||||
{
|
||||
License = formFile,
|
||||
Country = country,
|
||||
};
|
||||
|
||||
public IHeaderDictionary Headers => throw new NotImplementedException();
|
||||
|
||||
public long Length => throw new NotImplementedException();
|
||||
|
||||
public string Name => throw new NotImplementedException();
|
||||
|
||||
public string FileName => throw new NotImplementedException();
|
||||
|
||||
public void CopyTo(Stream target) => throw new NotImplementedException();
|
||||
public Task CopyToAsync(Stream target, CancellationToken cancellationToken = default) => throw new NotImplementedException();
|
||||
public Stream OpenReadStream() => throw new NotImplementedException();
|
||||
Assert.Equal(expected, sut.Validate(gs));
|
||||
}
|
||||
}
|
||||
|
||||
public class NotImplementedFormFile : IFormFile
|
||||
{
|
||||
public string ContentType => throw new NotImplementedException();
|
||||
|
||||
public string ContentDisposition => throw new NotImplementedException();
|
||||
|
||||
public IHeaderDictionary Headers => throw new NotImplementedException();
|
||||
|
||||
public long Length => throw new NotImplementedException();
|
||||
|
||||
public string Name => throw new NotImplementedException();
|
||||
|
||||
public string FileName => throw new NotImplementedException();
|
||||
|
||||
public void CopyTo(Stream target) => throw new NotImplementedException();
|
||||
public Task CopyToAsync(Stream target, CancellationToken cancellationToken = default) => throw new NotImplementedException();
|
||||
public Stream OpenReadStream() => throw new NotImplementedException();
|
||||
}
|
||||
|
@ -7,54 +7,53 @@ using Bit.Test.Common.Helpers;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Models.Request
|
||||
namespace Bit.Api.Test.Models.Request;
|
||||
|
||||
public class SendRequestModelTests
|
||||
{
|
||||
public class SendRequestModelTests
|
||||
[Fact]
|
||||
public void ToSend_Text_Success()
|
||||
{
|
||||
[Fact]
|
||||
public void ToSend_Text_Success()
|
||||
var deletionDate = DateTime.UtcNow.AddDays(5);
|
||||
var sendRequest = new SendRequestModel
|
||||
{
|
||||
var deletionDate = DateTime.UtcNow.AddDays(5);
|
||||
var sendRequest = new SendRequestModel
|
||||
DeletionDate = deletionDate,
|
||||
Disabled = false,
|
||||
ExpirationDate = null,
|
||||
HideEmail = false,
|
||||
Key = "encrypted_key",
|
||||
MaxAccessCount = null,
|
||||
Name = "encrypted_name",
|
||||
Notes = null,
|
||||
Password = "Password",
|
||||
Text = new SendTextModel()
|
||||
{
|
||||
DeletionDate = deletionDate,
|
||||
Disabled = false,
|
||||
ExpirationDate = null,
|
||||
HideEmail = false,
|
||||
Key = "encrypted_key",
|
||||
MaxAccessCount = null,
|
||||
Name = "encrypted_name",
|
||||
Notes = null,
|
||||
Password = "Password",
|
||||
Text = new SendTextModel()
|
||||
{
|
||||
Hidden = false,
|
||||
Text = "encrypted_text"
|
||||
},
|
||||
Type = SendType.Text,
|
||||
};
|
||||
Hidden = false,
|
||||
Text = "encrypted_text"
|
||||
},
|
||||
Type = SendType.Text,
|
||||
};
|
||||
|
||||
var sendService = Substitute.For<ISendService>();
|
||||
sendService.HashPassword(Arg.Any<string>())
|
||||
.Returns((info) => $"hashed_{(string)info[0]}");
|
||||
var sendService = Substitute.For<ISendService>();
|
||||
sendService.HashPassword(Arg.Any<string>())
|
||||
.Returns((info) => $"hashed_{(string)info[0]}");
|
||||
|
||||
var send = sendRequest.ToSend(Guid.NewGuid(), sendService);
|
||||
var send = sendRequest.ToSend(Guid.NewGuid(), sendService);
|
||||
|
||||
Assert.Equal(deletionDate, send.DeletionDate);
|
||||
Assert.False(send.Disabled);
|
||||
Assert.Null(send.ExpirationDate);
|
||||
Assert.False(send.HideEmail);
|
||||
Assert.Equal("encrypted_key", send.Key);
|
||||
Assert.Equal("hashed_Password", send.Password);
|
||||
Assert.Equal(deletionDate, send.DeletionDate);
|
||||
Assert.False(send.Disabled);
|
||||
Assert.Null(send.ExpirationDate);
|
||||
Assert.False(send.HideEmail);
|
||||
Assert.Equal("encrypted_key", send.Key);
|
||||
Assert.Equal("hashed_Password", send.Password);
|
||||
|
||||
using var jsonDocument = JsonDocument.Parse(send.Data);
|
||||
var root = jsonDocument.RootElement;
|
||||
var text = AssertHelper.AssertJsonProperty(root, "Text", JsonValueKind.String).GetString();
|
||||
Assert.Equal("encrypted_text", text);
|
||||
AssertHelper.AssertJsonProperty(root, "Hidden", JsonValueKind.False);
|
||||
Assert.False(root.TryGetProperty("Notes", out var _));
|
||||
var name = AssertHelper.AssertJsonProperty(root, "Name", JsonValueKind.String).GetString();
|
||||
Assert.Equal("encrypted_name", name);
|
||||
}
|
||||
using var jsonDocument = JsonDocument.Parse(send.Data);
|
||||
var root = jsonDocument.RootElement;
|
||||
var text = AssertHelper.AssertJsonProperty(root, "Text", JsonValueKind.String).GetString();
|
||||
Assert.Equal("encrypted_text", text);
|
||||
AssertHelper.AssertJsonProperty(root, "Hidden", JsonValueKind.False);
|
||||
Assert.False(root.TryGetProperty("Notes", out var _));
|
||||
var name = AssertHelper.AssertJsonProperty(root, "Name", JsonValueKind.String).GetString();
|
||||
Assert.Equal("encrypted_name", name);
|
||||
}
|
||||
}
|
||||
|
@ -5,23 +5,22 @@ using Microsoft.AspNetCore.Http;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Utilities
|
||||
namespace Bit.Api.Test.Utilities;
|
||||
|
||||
public class ApiHelpersTests
|
||||
{
|
||||
public class ApiHelpersTests
|
||||
[Fact]
|
||||
public async Task ReadJsonFileFromBody_Success()
|
||||
{
|
||||
[Fact]
|
||||
public async Task ReadJsonFileFromBody_Success()
|
||||
{
|
||||
var context = Substitute.For<HttpContext>();
|
||||
context.Request.ContentLength.Returns(200);
|
||||
var bytes = Encoding.UTF8.GetBytes(testFile);
|
||||
var formFile = new FormFile(new MemoryStream(bytes), 0, bytes.Length, "bitwarden_organization_license", "bitwarden_organization_license.json");
|
||||
var context = Substitute.For<HttpContext>();
|
||||
context.Request.ContentLength.Returns(200);
|
||||
var bytes = Encoding.UTF8.GetBytes(testFile);
|
||||
var formFile = new FormFile(new MemoryStream(bytes), 0, bytes.Length, "bitwarden_organization_license", "bitwarden_organization_license.json");
|
||||
|
||||
|
||||
var license = await ApiHelpers.ReadJsonFileFromBody<OrganizationLicense>(context, formFile);
|
||||
Assert.Equal(8, license.Version);
|
||||
}
|
||||
|
||||
const string testFile = "{\"licenseKey\": \"licenseKey\", \"installationId\": \"6285f891-b2ec-4047-84c5-2eb7f7747e74\", \"id\": \"1065216d-5854-4326-838d-635487f30b43\",\"name\": \"Test Org\",\"billingEmail\": \"test@email.com\",\"businessName\": null,\"enabled\": true, \"plan\": \"Enterprise (Annually)\",\"planType\": 11,\"seats\": 6,\"maxCollections\": null,\"usePolicies\": true,\"useSso\": true,\"useKeyConnector\": false,\"useGroups\": true,\"useEvents\": true,\"useDirectory\": true,\"useTotp\": true,\"use2fa\": true,\"useApi\": true,\"useResetPassword\": true,\"maxStorageGb\": 1,\"selfHost\": true,\"usersGetPremium\": true,\"version\": 8,\"issued\": \"2022-01-25T21:58:38.9454581Z\",\"refresh\": \"2022-01-28T14:26:31Z\",\"expires\": \"2022-01-28T14:26:31Z\",\"trial\": true,\"hash\": \"testvalue\",\"signature\": \"signature\"}";
|
||||
var license = await ApiHelpers.ReadJsonFileFromBody<OrganizationLicense>(context, formFile);
|
||||
Assert.Equal(8, license.Version);
|
||||
}
|
||||
|
||||
const string testFile = "{\"licenseKey\": \"licenseKey\", \"installationId\": \"6285f891-b2ec-4047-84c5-2eb7f7747e74\", \"id\": \"1065216d-5854-4326-838d-635487f30b43\",\"name\": \"Test Org\",\"billingEmail\": \"test@email.com\",\"businessName\": null,\"enabled\": true, \"plan\": \"Enterprise (Annually)\",\"planType\": 11,\"seats\": 6,\"maxCollections\": null,\"usePolicies\": true,\"useSso\": true,\"useKeyConnector\": false,\"useGroups\": true,\"useEvents\": true,\"useDirectory\": true,\"useTotp\": true,\"use2fa\": true,\"useApi\": true,\"useResetPassword\": true,\"maxStorageGb\": 1,\"selfHost\": true,\"usersGetPremium\": true,\"version\": 8,\"issued\": \"2022-01-25T21:58:38.9454581Z\",\"refresh\": \"2022-01-28T14:26:31Z\",\"expires\": \"2022-01-28T14:26:31Z\",\"trial\": true,\"hash\": \"testvalue\",\"signature\": \"signature\"}";
|
||||
}
|
||||
|
@ -10,71 +10,70 @@ using Microsoft.Extensions.Options;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Billing.Test.Controllers
|
||||
namespace Bit.Billing.Test.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(FreshdeskController))]
|
||||
[SutProviderCustomize]
|
||||
public class FreshdeskControllerTests
|
||||
{
|
||||
[ControllerCustomize(typeof(FreshdeskController))]
|
||||
[SutProviderCustomize]
|
||||
public class FreshdeskControllerTests
|
||||
private const string ApiKey = "TESTFRESHDESKAPIKEY";
|
||||
private const string WebhookKey = "TESTKEY";
|
||||
|
||||
[Theory]
|
||||
[BitAutoData((string)null, null)]
|
||||
[BitAutoData((string)null)]
|
||||
[BitAutoData(WebhookKey, null)]
|
||||
public async Task PostWebhook_NullRequiredParameters_BadRequest(string freshdeskWebhookKey, FreshdeskWebhookModel model,
|
||||
BillingSettings billingSettings, SutProvider<FreshdeskController> sutProvider)
|
||||
{
|
||||
private const string ApiKey = "TESTFRESHDESKAPIKEY";
|
||||
private const string WebhookKey = "TESTKEY";
|
||||
sutProvider.GetDependency<IOptions<BillingSettings>>().Value.FreshdeskWebhookKey.Returns(billingSettings.FreshdeskWebhookKey);
|
||||
|
||||
[Theory]
|
||||
[BitAutoData((string)null, null)]
|
||||
[BitAutoData((string)null)]
|
||||
[BitAutoData(WebhookKey, null)]
|
||||
public async Task PostWebhook_NullRequiredParameters_BadRequest(string freshdeskWebhookKey, FreshdeskWebhookModel model,
|
||||
BillingSettings billingSettings, SutProvider<FreshdeskController> sutProvider)
|
||||
var response = await sutProvider.Sut.PostWebhook(freshdeskWebhookKey, model);
|
||||
|
||||
var statusCodeResult = Assert.IsAssignableFrom<StatusCodeResult>(response);
|
||||
Assert.Equal(StatusCodes.Status400BadRequest, statusCodeResult.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PostWebhook_Success(User user, FreshdeskWebhookModel model,
|
||||
List<Organization> organizations, SutProvider<FreshdeskController> sutProvider)
|
||||
{
|
||||
model.TicketContactEmail = user.Email;
|
||||
|
||||
sutProvider.GetDependency<IUserRepository>().GetByEmailAsync(user.Email).Returns(user);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetManyByUserIdAsync(user.Id).Returns(organizations);
|
||||
|
||||
var mockHttpMessageHandler = Substitute.ForPartsOf<MockHttpMessageHandler>();
|
||||
var mockResponse = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
|
||||
mockHttpMessageHandler.Send(Arg.Any<HttpRequestMessage>(), Arg.Any<CancellationToken>())
|
||||
.Returns(mockResponse);
|
||||
var httpClient = new HttpClient(mockHttpMessageHandler);
|
||||
|
||||
sutProvider.GetDependency<IHttpClientFactory>().CreateClient("FreshdeskApi").Returns(httpClient);
|
||||
|
||||
sutProvider.GetDependency<IOptions<BillingSettings>>().Value.FreshdeskWebhookKey.Returns(WebhookKey);
|
||||
sutProvider.GetDependency<IOptions<BillingSettings>>().Value.FreshdeskApiKey.Returns(ApiKey);
|
||||
|
||||
var response = await sutProvider.Sut.PostWebhook(WebhookKey, model);
|
||||
|
||||
var statusCodeResult = Assert.IsAssignableFrom<StatusCodeResult>(response);
|
||||
Assert.Equal(StatusCodes.Status200OK, statusCodeResult.StatusCode);
|
||||
|
||||
_ = mockHttpMessageHandler.Received(1).Send(Arg.Is<HttpRequestMessage>(m => m.Method == HttpMethod.Put && m.RequestUri.ToString().EndsWith(model.TicketId)), Arg.Any<CancellationToken>());
|
||||
_ = mockHttpMessageHandler.Received(1).Send(Arg.Is<HttpRequestMessage>(m => m.Method == HttpMethod.Post && m.RequestUri.ToString().EndsWith($"{model.TicketId}/notes")), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
public class MockHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
sutProvider.GetDependency<IOptions<BillingSettings>>().Value.FreshdeskWebhookKey.Returns(billingSettings.FreshdeskWebhookKey);
|
||||
|
||||
var response = await sutProvider.Sut.PostWebhook(freshdeskWebhookKey, model);
|
||||
|
||||
var statusCodeResult = Assert.IsAssignableFrom<StatusCodeResult>(response);
|
||||
Assert.Equal(StatusCodes.Status400BadRequest, statusCodeResult.StatusCode);
|
||||
return Send(request, cancellationToken);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PostWebhook_Success(User user, FreshdeskWebhookModel model,
|
||||
List<Organization> organizations, SutProvider<FreshdeskController> sutProvider)
|
||||
public virtual Task<HttpResponseMessage> Send(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
model.TicketContactEmail = user.Email;
|
||||
|
||||
sutProvider.GetDependency<IUserRepository>().GetByEmailAsync(user.Email).Returns(user);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetManyByUserIdAsync(user.Id).Returns(organizations);
|
||||
|
||||
var mockHttpMessageHandler = Substitute.ForPartsOf<MockHttpMessageHandler>();
|
||||
var mockResponse = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
|
||||
mockHttpMessageHandler.Send(Arg.Any<HttpRequestMessage>(), Arg.Any<CancellationToken>())
|
||||
.Returns(mockResponse);
|
||||
var httpClient = new HttpClient(mockHttpMessageHandler);
|
||||
|
||||
sutProvider.GetDependency<IHttpClientFactory>().CreateClient("FreshdeskApi").Returns(httpClient);
|
||||
|
||||
sutProvider.GetDependency<IOptions<BillingSettings>>().Value.FreshdeskWebhookKey.Returns(WebhookKey);
|
||||
sutProvider.GetDependency<IOptions<BillingSettings>>().Value.FreshdeskApiKey.Returns(ApiKey);
|
||||
|
||||
var response = await sutProvider.Sut.PostWebhook(WebhookKey, model);
|
||||
|
||||
var statusCodeResult = Assert.IsAssignableFrom<StatusCodeResult>(response);
|
||||
Assert.Equal(StatusCodes.Status200OK, statusCodeResult.StatusCode);
|
||||
|
||||
_ = mockHttpMessageHandler.Received(1).Send(Arg.Is<HttpRequestMessage>(m => m.Method == HttpMethod.Put && m.RequestUri.ToString().EndsWith(model.TicketId)), Arg.Any<CancellationToken>());
|
||||
_ = mockHttpMessageHandler.Received(1).Send(Arg.Is<HttpRequestMessage>(m => m.Method == HttpMethod.Post && m.RequestUri.ToString().EndsWith($"{model.TicketId}/notes")), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
public class MockHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
return Send(request, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual Task<HttpResponseMessage> Send(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,73 +10,72 @@ using Microsoft.Extensions.Options;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Billing.Test.Controllers
|
||||
namespace Bit.Billing.Test.Controllers;
|
||||
|
||||
public class FreshsalesControllerTests
|
||||
{
|
||||
public class FreshsalesControllerTests
|
||||
private const string ApiKey = "TEST_FRESHSALES_APIKEY";
|
||||
private const string TestLead = "TEST_FRESHSALES_TESTLEAD";
|
||||
|
||||
private static (FreshsalesController, IUserRepository, IOrganizationRepository) CreateSut(
|
||||
string freshsalesApiKey)
|
||||
{
|
||||
private const string ApiKey = "TEST_FRESHSALES_APIKEY";
|
||||
private const string TestLead = "TEST_FRESHSALES_TESTLEAD";
|
||||
var userRepository = Substitute.For<IUserRepository>();
|
||||
var organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
|
||||
private static (FreshsalesController, IUserRepository, IOrganizationRepository) CreateSut(
|
||||
string freshsalesApiKey)
|
||||
var billingSettings = Options.Create(new BillingSettings
|
||||
{
|
||||
var userRepository = Substitute.For<IUserRepository>();
|
||||
var organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
FreshsalesApiKey = freshsalesApiKey,
|
||||
});
|
||||
var globalSettings = new GlobalSettings();
|
||||
globalSettings.BaseServiceUri.Admin = "https://test.com";
|
||||
|
||||
var billingSettings = Options.Create(new BillingSettings
|
||||
{
|
||||
FreshsalesApiKey = freshsalesApiKey,
|
||||
});
|
||||
var globalSettings = new GlobalSettings();
|
||||
globalSettings.BaseServiceUri.Admin = "https://test.com";
|
||||
var sut = new FreshsalesController(
|
||||
userRepository,
|
||||
organizationRepository,
|
||||
billingSettings,
|
||||
Substitute.For<ILogger<FreshsalesController>>(),
|
||||
globalSettings
|
||||
);
|
||||
|
||||
var sut = new FreshsalesController(
|
||||
userRepository,
|
||||
organizationRepository,
|
||||
billingSettings,
|
||||
Substitute.For<ILogger<FreshsalesController>>(),
|
||||
globalSettings
|
||||
);
|
||||
return (sut, userRepository, organizationRepository);
|
||||
}
|
||||
|
||||
return (sut, userRepository, organizationRepository);
|
||||
}
|
||||
[RequiredEnvironmentTheory(ApiKey, TestLead), EnvironmentData(ApiKey, TestLead)]
|
||||
public async Task PostWebhook_Success(string freshsalesApiKey, long leadId)
|
||||
{
|
||||
// This test is only for development to use:
|
||||
// `export TEST_FRESHSALES_APIKEY=[apikey]`
|
||||
// `export TEST_FRESHSALES_TESTLEAD=[lead id]`
|
||||
// `dotnet test --filter "FullyQualifiedName~FreshsalesControllerTests.PostWebhook_Success"`
|
||||
var (sut, userRepository, organizationRepository) = CreateSut(freshsalesApiKey);
|
||||
|
||||
[RequiredEnvironmentTheory(ApiKey, TestLead), EnvironmentData(ApiKey, TestLead)]
|
||||
public async Task PostWebhook_Success(string freshsalesApiKey, long leadId)
|
||||
var user = new User
|
||||
{
|
||||
// This test is only for development to use:
|
||||
// `export TEST_FRESHSALES_APIKEY=[apikey]`
|
||||
// `export TEST_FRESHSALES_TESTLEAD=[lead id]`
|
||||
// `dotnet test --filter "FullyQualifiedName~FreshsalesControllerTests.PostWebhook_Success"`
|
||||
var (sut, userRepository, organizationRepository) = CreateSut(freshsalesApiKey);
|
||||
Id = Guid.NewGuid(),
|
||||
Email = "test@email.com",
|
||||
Premium = true,
|
||||
};
|
||||
|
||||
var user = new User
|
||||
userRepository.GetByEmailAsync(user.Email)
|
||||
.Returns(user);
|
||||
|
||||
organizationRepository.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(new List<Organization>
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Email = "test@email.com",
|
||||
Premium = true,
|
||||
};
|
||||
|
||||
userRepository.GetByEmailAsync(user.Email)
|
||||
.Returns(user);
|
||||
|
||||
organizationRepository.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(new List<Organization>
|
||||
new Organization
|
||||
{
|
||||
new Organization
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = "Test Org",
|
||||
}
|
||||
});
|
||||
Id = Guid.NewGuid(),
|
||||
Name = "Test Org",
|
||||
}
|
||||
});
|
||||
|
||||
var response = await sut.PostWebhook(freshsalesApiKey, new CustomWebhookRequestModel
|
||||
{
|
||||
LeadId = leadId,
|
||||
}, new CancellationToken(false));
|
||||
var response = await sut.PostWebhook(freshsalesApiKey, new CustomWebhookRequestModel
|
||||
{
|
||||
LeadId = leadId,
|
||||
}, new CancellationToken(false));
|
||||
|
||||
var statusCodeResult = Assert.IsAssignableFrom<StatusCodeResult>(response);
|
||||
Assert.Equal(StatusCodes.Status204NoContent, statusCodeResult.StatusCode);
|
||||
}
|
||||
var statusCodeResult = Assert.IsAssignableFrom<StatusCodeResult>(response);
|
||||
Assert.Equal(StatusCodes.Status204NoContent, statusCodeResult.StatusCode);
|
||||
}
|
||||
}
|
||||
|
@ -3,26 +3,25 @@ using AutoFixture;
|
||||
using Bit.Test.Common.Helpers;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
[DataDiscoverer("AutoFixture.Xunit2.NoPreDiscoveryDataDiscoverer", "AutoFixture.Xunit2")]
|
||||
public class BitAutoDataAttribute : DataAttribute
|
||||
{
|
||||
[DataDiscoverer("AutoFixture.Xunit2.NoPreDiscoveryDataDiscoverer", "AutoFixture.Xunit2")]
|
||||
public class BitAutoDataAttribute : DataAttribute
|
||||
private readonly Func<IFixture> _createFixture;
|
||||
private readonly object[] _fixedTestParameters;
|
||||
|
||||
public BitAutoDataAttribute(params object[] fixedTestParameters) :
|
||||
this(() => new Fixture(), fixedTestParameters)
|
||||
{ }
|
||||
|
||||
public BitAutoDataAttribute(Func<IFixture> createFixture, params object[] fixedTestParameters) :
|
||||
base()
|
||||
{
|
||||
private readonly Func<IFixture> _createFixture;
|
||||
private readonly object[] _fixedTestParameters;
|
||||
|
||||
public BitAutoDataAttribute(params object[] fixedTestParameters) :
|
||||
this(() => new Fixture(), fixedTestParameters)
|
||||
{ }
|
||||
|
||||
public BitAutoDataAttribute(Func<IFixture> createFixture, params object[] fixedTestParameters) :
|
||||
base()
|
||||
{
|
||||
_createFixture = createFixture;
|
||||
_fixedTestParameters = fixedTestParameters;
|
||||
}
|
||||
|
||||
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
|
||||
=> BitAutoDataAttributeHelpers.GetData(testMethod, _createFixture(), _fixedTestParameters);
|
||||
_createFixture = createFixture;
|
||||
_fixedTestParameters = fixedTestParameters;
|
||||
}
|
||||
|
||||
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
|
||||
=> BitAutoDataAttributeHelpers.GetData(testMethod, _createFixture(), _fixedTestParameters);
|
||||
}
|
||||
|
@ -1,21 +1,20 @@
|
||||
using AutoFixture;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Base class for customizing parameters in methods decorated with the
|
||||
/// Bit.Test.Common.AutoFixture.Attributes.MemberAutoDataAttribute.
|
||||
/// </para>
|
||||
/// ⚠ Warning ⚠ Will not insert customizations into AutoFixture's AutoDataAttribute build chain
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = true)]
|
||||
public abstract class BitCustomizeAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Base class for customizing parameters in methods decorated with the
|
||||
/// Bit.Test.Common.AutoFixture.Attributes.MemberAutoDataAttribute.
|
||||
/// </para>
|
||||
/// ⚠ Warning ⚠ Will not insert customizations into AutoFixture's AutoDataAttribute build chain
|
||||
/// /// Gets a customization for the method's parameters.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = true)]
|
||||
public abstract class BitCustomizeAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// /// Gets a customization for the method's parameters.
|
||||
/// </summary>
|
||||
/// <returns>A customization for the method's paramters.</returns>
|
||||
public abstract ICustomization GetCustomization();
|
||||
}
|
||||
/// <returns>A customization for the method's paramters.</returns>
|
||||
public abstract ICustomization GetCustomization();
|
||||
}
|
||||
|
@ -3,23 +3,22 @@ using AutoFixture;
|
||||
using Bit.Test.Common.Helpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
public class BitMemberAutoDataAttribute : MemberDataAttributeBase
|
||||
{
|
||||
public class BitMemberAutoDataAttribute : MemberDataAttributeBase
|
||||
private readonly Func<IFixture> _createFixture;
|
||||
|
||||
public BitMemberAutoDataAttribute(string memberName, params object[] parameters) :
|
||||
this(() => new Fixture(), memberName, parameters)
|
||||
{ }
|
||||
|
||||
public BitMemberAutoDataAttribute(Func<IFixture> createFixture, string memberName, params object[] parameters) :
|
||||
base(memberName, parameters)
|
||||
{
|
||||
private readonly Func<IFixture> _createFixture;
|
||||
|
||||
public BitMemberAutoDataAttribute(string memberName, params object[] parameters) :
|
||||
this(() => new Fixture(), memberName, parameters)
|
||||
{ }
|
||||
|
||||
public BitMemberAutoDataAttribute(Func<IFixture> createFixture, string memberName, params object[] parameters) :
|
||||
base(memberName, parameters)
|
||||
{
|
||||
_createFixture = createFixture;
|
||||
}
|
||||
|
||||
protected override object[] ConvertDataItem(MethodInfo testMethod, object item) =>
|
||||
BitAutoDataAttributeHelpers.GetData(testMethod, _createFixture(), item as object[]).First();
|
||||
_createFixture = createFixture;
|
||||
}
|
||||
|
||||
protected override object[] ConvertDataItem(MethodInfo testMethod, object item) =>
|
||||
BitAutoDataAttributeHelpers.GetData(testMethod, _createFixture(), item as object[]).First();
|
||||
}
|
||||
|
@ -1,23 +1,22 @@
|
||||
using AutoFixture;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Disables setting of Auto Properties on the Controller to avoid ASP.net initialization errors from a mock environment. Still sets constructor dependencies.
|
||||
/// </summary>
|
||||
public class ControllerCustomizeAttribute : BitCustomizeAttribute
|
||||
{
|
||||
private readonly Type _controllerType;
|
||||
|
||||
/// <summary>
|
||||
/// Disables setting of Auto Properties on the Controller to avoid ASP.net initialization errors from a mock environment. Still sets constructor dependencies.
|
||||
/// Initialize an instance of the ControllerCustomizeAttribute class
|
||||
/// </summary>
|
||||
public class ControllerCustomizeAttribute : BitCustomizeAttribute
|
||||
/// <param name="controllerType">The Type of the controller to allow autofixture to create</param>
|
||||
public ControllerCustomizeAttribute(Type controllerType)
|
||||
{
|
||||
private readonly Type _controllerType;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize an instance of the ControllerCustomizeAttribute class
|
||||
/// </summary>
|
||||
/// <param name="controllerType">The Type of the controller to allow autofixture to create</param>
|
||||
public ControllerCustomizeAttribute(Type controllerType)
|
||||
{
|
||||
_controllerType = controllerType;
|
||||
}
|
||||
|
||||
public override ICustomization GetCustomization() => new ControllerCustomization(_controllerType);
|
||||
_controllerType = controllerType;
|
||||
}
|
||||
|
||||
public override ICustomization GetCustomization() => new ControllerCustomization(_controllerType);
|
||||
}
|
||||
|
@ -1,23 +1,22 @@
|
||||
using AutoFixture;
|
||||
using AutoFixture.Xunit2;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes
|
||||
{
|
||||
public class CustomAutoDataAttribute : AutoDataAttribute
|
||||
{
|
||||
public CustomAutoDataAttribute(params Type[] iCustomizationTypes) : this(iCustomizationTypes
|
||||
.Select(t => (ICustomization)Activator.CreateInstance(t)).ToArray())
|
||||
{ }
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
public CustomAutoDataAttribute(params ICustomization[] customizations) : base(() =>
|
||||
public class CustomAutoDataAttribute : AutoDataAttribute
|
||||
{
|
||||
public CustomAutoDataAttribute(params Type[] iCustomizationTypes) : this(iCustomizationTypes
|
||||
.Select(t => (ICustomization)Activator.CreateInstance(t)).ToArray())
|
||||
{ }
|
||||
|
||||
public CustomAutoDataAttribute(params ICustomization[] customizations) : base(() =>
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
foreach (var customization in customizations)
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
foreach (var customization in customizations)
|
||||
{
|
||||
fixture.Customize(customization);
|
||||
}
|
||||
return fixture;
|
||||
})
|
||||
{ }
|
||||
}
|
||||
fixture.Customize(customization);
|
||||
}
|
||||
return fixture;
|
||||
})
|
||||
{ }
|
||||
}
|
||||
|
@ -1,43 +1,42 @@
|
||||
using System.Reflection;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Used for collecting data from environment useful for when we want to test an integration with another service and
|
||||
/// it might require an api key or other piece of sensitive data that we don't want slipping into the wrong hands.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It probably should be refactored to support fixtures and other customization so it can more easily be used in conjunction
|
||||
/// with more parameters. Currently it attempt to match environment variable names to values of the parameter type in that positions.
|
||||
/// It will start from the first parameter and go for each supplied name.
|
||||
/// </remarks>
|
||||
public class EnvironmentDataAttribute : DataAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Used for collecting data from environment useful for when we want to test an integration with another service and
|
||||
/// it might require an api key or other piece of sensitive data that we don't want slipping into the wrong hands.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It probably should be refactored to support fixtures and other customization so it can more easily be used in conjunction
|
||||
/// with more parameters. Currently it attempt to match environment variable names to values of the parameter type in that positions.
|
||||
/// It will start from the first parameter and go for each supplied name.
|
||||
/// </remarks>
|
||||
public class EnvironmentDataAttribute : DataAttribute
|
||||
private readonly string[] _environmentVariableNames;
|
||||
|
||||
public EnvironmentDataAttribute(params string[] environmentVariableNames)
|
||||
{
|
||||
private readonly string[] _environmentVariableNames;
|
||||
_environmentVariableNames = environmentVariableNames;
|
||||
}
|
||||
|
||||
public EnvironmentDataAttribute(params string[] environmentVariableNames)
|
||||
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
|
||||
{
|
||||
var methodParameters = testMethod.GetParameters();
|
||||
|
||||
if (methodParameters.Length < _environmentVariableNames.Length)
|
||||
{
|
||||
_environmentVariableNames = environmentVariableNames;
|
||||
throw new ArgumentException($"The target test method only has {methodParameters.Length} arguments but you supplied {_environmentVariableNames.Length}");
|
||||
}
|
||||
|
||||
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
|
||||
var values = new object[_environmentVariableNames.Length];
|
||||
|
||||
for (var i = 0; i < _environmentVariableNames.Length; i++)
|
||||
{
|
||||
var methodParameters = testMethod.GetParameters();
|
||||
|
||||
if (methodParameters.Length < _environmentVariableNames.Length)
|
||||
{
|
||||
throw new ArgumentException($"The target test method only has {methodParameters.Length} arguments but you supplied {_environmentVariableNames.Length}");
|
||||
}
|
||||
|
||||
var values = new object[_environmentVariableNames.Length];
|
||||
|
||||
for (var i = 0; i < _environmentVariableNames.Length; i++)
|
||||
{
|
||||
values[i] = Convert.ChangeType(Environment.GetEnvironmentVariable(_environmentVariableNames[i]), methodParameters[i].ParameterType);
|
||||
}
|
||||
|
||||
return new[] { values };
|
||||
values[i] = Convert.ChangeType(Environment.GetEnvironmentVariable(_environmentVariableNames[i]), methodParameters[i].ParameterType);
|
||||
}
|
||||
|
||||
return new[] { values };
|
||||
}
|
||||
}
|
||||
|
@ -3,20 +3,19 @@ using AutoFixture.Xunit2;
|
||||
using Xunit;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes
|
||||
{
|
||||
public class InlineCustomAutoDataAttribute : CompositeDataAttribute
|
||||
{
|
||||
public InlineCustomAutoDataAttribute(Type[] iCustomizationTypes, params object[] values) : base(new DataAttribute[] {
|
||||
new InlineDataAttribute(values),
|
||||
new CustomAutoDataAttribute(iCustomizationTypes)
|
||||
})
|
||||
{ }
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
public InlineCustomAutoDataAttribute(ICustomization[] customizations, params object[] values) : base(new DataAttribute[] {
|
||||
new InlineDataAttribute(values),
|
||||
new CustomAutoDataAttribute(customizations)
|
||||
})
|
||||
{ }
|
||||
}
|
||||
public class InlineCustomAutoDataAttribute : CompositeDataAttribute
|
||||
{
|
||||
public InlineCustomAutoDataAttribute(Type[] iCustomizationTypes, params object[] values) : base(new DataAttribute[] {
|
||||
new InlineDataAttribute(values),
|
||||
new CustomAutoDataAttribute(iCustomizationTypes)
|
||||
})
|
||||
{ }
|
||||
|
||||
public InlineCustomAutoDataAttribute(ICustomization[] customizations, params object[] values) : base(new DataAttribute[] {
|
||||
new InlineDataAttribute(values),
|
||||
new CustomAutoDataAttribute(customizations)
|
||||
})
|
||||
{ }
|
||||
}
|
||||
|
@ -1,18 +1,17 @@
|
||||
using AutoFixture;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes
|
||||
{
|
||||
public class InlineSutAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineSutAutoDataAttribute(params object[] values) : base(
|
||||
new Type[] { typeof(SutProviderCustomization) }, values)
|
||||
{ }
|
||||
public InlineSutAutoDataAttribute(Type[] iCustomizationTypes, params object[] values) : base(
|
||||
iCustomizationTypes.Append(typeof(SutProviderCustomization)).ToArray(), values)
|
||||
{ }
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
public InlineSutAutoDataAttribute(ICustomization[] customizations, params object[] values) : base(
|
||||
customizations.Append(new SutProviderCustomization()).ToArray(), values)
|
||||
{ }
|
||||
}
|
||||
public class InlineSutAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineSutAutoDataAttribute(params object[] values) : base(
|
||||
new Type[] { typeof(SutProviderCustomization) }, values)
|
||||
{ }
|
||||
public InlineSutAutoDataAttribute(Type[] iCustomizationTypes, params object[] values) : base(
|
||||
iCustomizationTypes.Append(typeof(SutProviderCustomization)).ToArray(), values)
|
||||
{ }
|
||||
|
||||
public InlineSutAutoDataAttribute(ICustomization[] customizations, params object[] values) : base(
|
||||
customizations.Append(new SutProviderCustomization()).ToArray(), values)
|
||||
{ }
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
using AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.JsonDocumentFixtures;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
public class JsonDocumentCustomizeAttribute : BitCustomizeAttribute
|
||||
{
|
||||
public class JsonDocumentCustomizeAttribute : BitCustomizeAttribute
|
||||
{
|
||||
public string Json { get; set; }
|
||||
public override ICustomization GetCustomization() => new JsonDocumentCustomization() { Json = Json };
|
||||
}
|
||||
public string Json { get; set; }
|
||||
public override ICustomization GetCustomization() => new JsonDocumentCustomization() { Json = Json };
|
||||
}
|
||||
|
@ -1,38 +1,37 @@
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Used for requiring certain environment variables exist at the time. Mostly used for more edge unit tests that shouldn't
|
||||
/// be run during CI builds or should only be ran in CI builds when pieces of information are available.
|
||||
/// </summary>
|
||||
public class RequiredEnvironmentTheoryAttribute : TheoryAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Used for requiring certain environment variables exist at the time. Mostly used for more edge unit tests that shouldn't
|
||||
/// be run during CI builds or should only be ran in CI builds when pieces of information are available.
|
||||
/// </summary>
|
||||
public class RequiredEnvironmentTheoryAttribute : TheoryAttribute
|
||||
private readonly string[] _environmentVariableNames;
|
||||
|
||||
public RequiredEnvironmentTheoryAttribute(params string[] environmentVariableNames)
|
||||
{
|
||||
private readonly string[] _environmentVariableNames;
|
||||
_environmentVariableNames = environmentVariableNames;
|
||||
|
||||
public RequiredEnvironmentTheoryAttribute(params string[] environmentVariableNames)
|
||||
if (!HasRequiredEnvironmentVariables())
|
||||
{
|
||||
_environmentVariableNames = environmentVariableNames;
|
||||
|
||||
if (!HasRequiredEnvironmentVariables())
|
||||
{
|
||||
Skip = $"Missing one or more required environment variables. ({string.Join(", ", _environmentVariableNames)})";
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasRequiredEnvironmentVariables()
|
||||
{
|
||||
foreach (var env in _environmentVariableNames)
|
||||
{
|
||||
var value = Environment.GetEnvironmentVariable(env);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
Skip = $"Missing one or more required environment variables. ({string.Join(", ", _environmentVariableNames)})";
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasRequiredEnvironmentVariables()
|
||||
{
|
||||
foreach (var env in _environmentVariableNames)
|
||||
{
|
||||
var value = Environment.GetEnvironmentVariable(env);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
using AutoFixture;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes
|
||||
{
|
||||
public class SutProviderCustomizeAttribute : BitCustomizeAttribute
|
||||
{
|
||||
public override ICustomization GetCustomization() => new SutProviderCustomization();
|
||||
}
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
public class SutAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public SutAutoDataAttribute(params Type[] iCustomizationTypes) : base(
|
||||
iCustomizationTypes.Append(typeof(SutProviderCustomization)).ToArray())
|
||||
{ }
|
||||
}
|
||||
public class SutProviderCustomizeAttribute : BitCustomizeAttribute
|
||||
{
|
||||
public override ICustomization GetCustomization() => new SutProviderCustomization();
|
||||
}
|
||||
|
||||
public class SutAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public SutAutoDataAttribute(params Type[] iCustomizationTypes) : base(
|
||||
iCustomizationTypes.Append(typeof(SutProviderCustomization)).ToArray())
|
||||
{ }
|
||||
}
|
||||
|
@ -1,39 +1,38 @@
|
||||
using AutoFixture;
|
||||
using AutoFixture.Kernel;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture
|
||||
namespace Bit.Test.Common.AutoFixture;
|
||||
|
||||
public class BuilderWithoutAutoProperties : ISpecimenBuilder
|
||||
{
|
||||
public class BuilderWithoutAutoProperties : ISpecimenBuilder
|
||||
private readonly Type _type;
|
||||
public BuilderWithoutAutoProperties(Type type)
|
||||
{
|
||||
private readonly Type _type;
|
||||
public BuilderWithoutAutoProperties(Type type)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var type = request as Type;
|
||||
if (type == null || type != _type)
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
var fixture = new Fixture();
|
||||
// This is the equivalent of _fixture.Build<_type>().OmitAutoProperties().Create(request, context), but no overload for
|
||||
// Build(Type type) exists.
|
||||
dynamic reflectedComposer = typeof(Fixture).GetMethod("Build").MakeGenericMethod(_type).Invoke(fixture, null);
|
||||
return reflectedComposer.OmitAutoProperties().Create(request, context);
|
||||
}
|
||||
_type = type;
|
||||
}
|
||||
public class BuilderWithoutAutoProperties<T> : ISpecimenBuilder
|
||||
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
{
|
||||
public object Create(object request, ISpecimenContext context) =>
|
||||
new BuilderWithoutAutoProperties(typeof(T)).Create(request, context);
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var type = request as Type;
|
||||
if (type == null || type != _type)
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
var fixture = new Fixture();
|
||||
// This is the equivalent of _fixture.Build<_type>().OmitAutoProperties().Create(request, context), but no overload for
|
||||
// Build(Type type) exists.
|
||||
dynamic reflectedComposer = typeof(Fixture).GetMethod("Build").MakeGenericMethod(_type).Invoke(fixture, null);
|
||||
return reflectedComposer.OmitAutoProperties().Create(request, context);
|
||||
}
|
||||
}
|
||||
public class BuilderWithoutAutoProperties<T> : ISpecimenBuilder
|
||||
{
|
||||
public object Create(object request, ISpecimenContext context) =>
|
||||
new BuilderWithoutAutoProperties(typeof(T)).Create(request, context);
|
||||
}
|
||||
|
@ -2,32 +2,31 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture
|
||||
namespace Bit.Test.Common.AutoFixture;
|
||||
|
||||
/// <summary>
|
||||
/// Disables setting of Auto Properties on the Controller to avoid ASP.net initialization errors. Still sets constructor dependencies.
|
||||
/// </summary>
|
||||
/// <param name="fixture"></param>
|
||||
public class ControllerCustomization : ICustomization
|
||||
{
|
||||
/// <summary>
|
||||
/// Disables setting of Auto Properties on the Controller to avoid ASP.net initialization errors. Still sets constructor dependencies.
|
||||
/// </summary>
|
||||
/// <param name="fixture"></param>
|
||||
public class ControllerCustomization : ICustomization
|
||||
private readonly Type _controllerType;
|
||||
public ControllerCustomization(Type controllerType)
|
||||
{
|
||||
private readonly Type _controllerType;
|
||||
public ControllerCustomization(Type controllerType)
|
||||
if (!controllerType.IsAssignableTo(typeof(Controller)))
|
||||
{
|
||||
if (!controllerType.IsAssignableTo(typeof(Controller)))
|
||||
{
|
||||
throw new InvalidParameterException($"{nameof(controllerType)} must derive from {typeof(Controller).Name}");
|
||||
}
|
||||
|
||||
_controllerType = controllerType;
|
||||
throw new InvalidParameterException($"{nameof(controllerType)} must derive from {typeof(Controller).Name}");
|
||||
}
|
||||
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customizations.Add(new BuilderWithoutAutoProperties(_controllerType));
|
||||
}
|
||||
_controllerType = controllerType;
|
||||
}
|
||||
public class ControllerCustomization<T> : ICustomization where T : Controller
|
||||
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
public void Customize(IFixture fixture) => new ControllerCustomization(typeof(T)).Customize(fixture);
|
||||
fixture.Customizations.Add(new BuilderWithoutAutoProperties(_controllerType));
|
||||
}
|
||||
}
|
||||
public class ControllerCustomization<T> : ICustomization where T : Controller
|
||||
{
|
||||
public void Customize(IFixture fixture) => new ControllerCustomization(typeof(T)).Customize(fixture);
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
using AutoFixture;
|
||||
using AutoFixture.AutoNSubstitute;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture
|
||||
{
|
||||
public static class FixtureExtensions
|
||||
{
|
||||
public static IFixture WithAutoNSubstitutions(this IFixture fixture)
|
||||
=> fixture.Customize(new AutoNSubstituteCustomization());
|
||||
namespace Bit.Test.Common.AutoFixture;
|
||||
|
||||
public static IFixture WithAutoNSubstitutionsAutoPopulatedProperties(this IFixture fixture)
|
||||
=> fixture.Customize(new AutoNSubstituteCustomization { ConfigureMembers = true });
|
||||
}
|
||||
public static class FixtureExtensions
|
||||
{
|
||||
public static IFixture WithAutoNSubstitutions(this IFixture fixture)
|
||||
=> fixture.Customize(new AutoNSubstituteCustomization());
|
||||
|
||||
public static IFixture WithAutoNSubstitutionsAutoPopulatedProperties(this IFixture fixture)
|
||||
=> fixture.Customize(new AutoNSubstituteCustomization { ConfigureMembers = true });
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
using AutoFixture;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture
|
||||
namespace Bit.Test.Common.AutoFixture;
|
||||
|
||||
public class GlobalSettings : ICustomization
|
||||
{
|
||||
public class GlobalSettings : ICustomization
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<Bit.Core.Settings.GlobalSettings>(composer => composer
|
||||
.Without(s => s.BaseServiceUri)
|
||||
.Without(s => s.Attachment)
|
||||
.Without(s => s.Send)
|
||||
.Without(s => s.DataProtection));
|
||||
}
|
||||
fixture.Customize<Bit.Core.Settings.GlobalSettings>(composer => composer
|
||||
.Without(s => s.BaseServiceUri)
|
||||
.Without(s => s.Attachment)
|
||||
.Without(s => s.Send)
|
||||
.Without(s => s.DataProtection));
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
namespace Bit.Test.Common.AutoFixture
|
||||
namespace Bit.Test.Common.AutoFixture;
|
||||
|
||||
public interface ISutProvider
|
||||
{
|
||||
public interface ISutProvider
|
||||
{
|
||||
Type SutType { get; }
|
||||
ISutProvider Create();
|
||||
}
|
||||
Type SutType { get; }
|
||||
ISutProvider Create();
|
||||
}
|
||||
|
@ -2,31 +2,30 @@
|
||||
using AutoFixture;
|
||||
using AutoFixture.Kernel;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture.JsonDocumentFixtures
|
||||
namespace Bit.Test.Common.AutoFixture.JsonDocumentFixtures;
|
||||
|
||||
public class JsonDocumentCustomization : ICustomization, ISpecimenBuilder
|
||||
{
|
||||
public class JsonDocumentCustomization : ICustomization, ISpecimenBuilder
|
||||
|
||||
public string Json { get; set; }
|
||||
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customizations.Add(this);
|
||||
}
|
||||
|
||||
public string Json { get; set; }
|
||||
|
||||
public void Customize(IFixture fixture)
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
fixture.Customizations.Add(this);
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
var type = request as Type;
|
||||
if (type == null || (type != typeof(JsonDocument)))
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
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(JsonDocument)))
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
return JsonDocument.Parse(Json ?? "{}");
|
||||
}
|
||||
return JsonDocument.Parse(Json ?? "{}");
|
||||
}
|
||||
}
|
||||
|
@ -2,133 +2,132 @@
|
||||
using AutoFixture;
|
||||
using AutoFixture.Kernel;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture
|
||||
namespace Bit.Test.Common.AutoFixture;
|
||||
|
||||
public class SutProvider<TSut> : ISutProvider
|
||||
{
|
||||
public class SutProvider<TSut> : ISutProvider
|
||||
private Dictionary<Type, Dictionary<string, object>> _dependencies;
|
||||
private readonly IFixture _fixture;
|
||||
private readonly ConstructorParameterRelay<TSut> _constructorParameterRelay;
|
||||
|
||||
public TSut Sut { get; private set; }
|
||||
public Type SutType => typeof(TSut);
|
||||
|
||||
public SutProvider() : this(new Fixture()) { }
|
||||
|
||||
public SutProvider(IFixture fixture)
|
||||
{
|
||||
private Dictionary<Type, Dictionary<string, object>> _dependencies;
|
||||
_dependencies = new Dictionary<Type, Dictionary<string, object>>();
|
||||
_fixture = (fixture ?? new Fixture()).WithAutoNSubstitutions().Customize(new GlobalSettings());
|
||||
_constructorParameterRelay = new ConstructorParameterRelay<TSut>(this, _fixture);
|
||||
_fixture.Customizations.Add(_constructorParameterRelay);
|
||||
}
|
||||
|
||||
public SutProvider<TSut> SetDependency<T>(T dependency, string parameterName = "")
|
||||
=> SetDependency(typeof(T), dependency, parameterName);
|
||||
public SutProvider<TSut> SetDependency(Type dependencyType, object dependency, string parameterName = "")
|
||||
{
|
||||
if (_dependencies.ContainsKey(dependencyType))
|
||||
{
|
||||
_dependencies[dependencyType][parameterName] = dependency;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dependencies[dependencyType] = new Dictionary<string, object> { { parameterName, dependency } };
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public T GetDependency<T>(string parameterName = "") => (T)GetDependency(typeof(T), parameterName);
|
||||
public object GetDependency(Type dependencyType, string parameterName = "")
|
||||
{
|
||||
if (DependencyIsSet(dependencyType, parameterName))
|
||||
{
|
||||
return _dependencies[dependencyType][parameterName];
|
||||
}
|
||||
else if (_dependencies.ContainsKey(dependencyType))
|
||||
{
|
||||
var knownDependencies = _dependencies[dependencyType];
|
||||
if (knownDependencies.Values.Count == 1)
|
||||
{
|
||||
return _dependencies[dependencyType].Values.Single();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(string.Concat($"Dependency of type {dependencyType.Name} and name ",
|
||||
$"{parameterName} does not exist. Available dependency names are: ",
|
||||
string.Join(", ", knownDependencies.Keys)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Dependency of type {dependencyType.Name} and name {parameterName} has not been set.");
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_dependencies = new Dictionary<Type, Dictionary<string, object>>();
|
||||
Sut = default;
|
||||
}
|
||||
|
||||
ISutProvider ISutProvider.Create() => Create();
|
||||
public SutProvider<TSut> Create()
|
||||
{
|
||||
Sut = _fixture.Create<TSut>();
|
||||
return this;
|
||||
}
|
||||
|
||||
private bool DependencyIsSet(Type dependencyType, string parameterName = "")
|
||||
=> _dependencies.ContainsKey(dependencyType) && _dependencies[dependencyType].ContainsKey(parameterName);
|
||||
|
||||
private object GetDefault(Type type) => type.IsValueType ? Activator.CreateInstance(type) : null;
|
||||
|
||||
private class ConstructorParameterRelay<T> : ISpecimenBuilder
|
||||
{
|
||||
private readonly SutProvider<T> _sutProvider;
|
||||
private readonly IFixture _fixture;
|
||||
private readonly ConstructorParameterRelay<TSut> _constructorParameterRelay;
|
||||
|
||||
public TSut Sut { get; private set; }
|
||||
public Type SutType => typeof(TSut);
|
||||
|
||||
public SutProvider() : this(new Fixture()) { }
|
||||
|
||||
public SutProvider(IFixture fixture)
|
||||
public ConstructorParameterRelay(SutProvider<T> sutProvider, IFixture fixture)
|
||||
{
|
||||
_dependencies = new Dictionary<Type, Dictionary<string, object>>();
|
||||
_fixture = (fixture ?? new Fixture()).WithAutoNSubstitutions().Customize(new GlobalSettings());
|
||||
_constructorParameterRelay = new ConstructorParameterRelay<TSut>(this, _fixture);
|
||||
_fixture.Customizations.Add(_constructorParameterRelay);
|
||||
_sutProvider = sutProvider;
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
public SutProvider<TSut> SetDependency<T>(T dependency, string parameterName = "")
|
||||
=> SetDependency(typeof(T), dependency, parameterName);
|
||||
public SutProvider<TSut> SetDependency(Type dependencyType, object dependency, string parameterName = "")
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
{
|
||||
if (_dependencies.ContainsKey(dependencyType))
|
||||
if (context == null)
|
||||
{
|
||||
_dependencies[dependencyType][parameterName] = dependency;
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
else
|
||||
if (!(request is ParameterInfo parameterInfo))
|
||||
{
|
||||
_dependencies[dependencyType] = new Dictionary<string, object> { { parameterName, dependency } };
|
||||
return new NoSpecimen();
|
||||
}
|
||||
if (parameterInfo.Member.DeclaringType != typeof(T) ||
|
||||
parameterInfo.Member.MemberType != MemberTypes.Constructor)
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public T GetDependency<T>(string parameterName = "") => (T)GetDependency(typeof(T), parameterName);
|
||||
public object GetDependency(Type dependencyType, string parameterName = "")
|
||||
{
|
||||
if (DependencyIsSet(dependencyType, parameterName))
|
||||
if (_sutProvider.DependencyIsSet(parameterInfo.ParameterType, parameterInfo.Name))
|
||||
{
|
||||
return _dependencies[dependencyType][parameterName];
|
||||
return _sutProvider.GetDependency(parameterInfo.ParameterType, parameterInfo.Name);
|
||||
}
|
||||
else if (_dependencies.ContainsKey(dependencyType))
|
||||
// Return default type if set
|
||||
else if (_sutProvider.DependencyIsSet(parameterInfo.ParameterType, ""))
|
||||
{
|
||||
var knownDependencies = _dependencies[dependencyType];
|
||||
if (knownDependencies.Values.Count == 1)
|
||||
{
|
||||
return _dependencies[dependencyType].Values.Single();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(string.Concat($"Dependency of type {dependencyType.Name} and name ",
|
||||
$"{parameterName} does not exist. Available dependency names are: ",
|
||||
string.Join(", ", knownDependencies.Keys)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Dependency of type {dependencyType.Name} and name {parameterName} has not been set.");
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_dependencies = new Dictionary<Type, Dictionary<string, object>>();
|
||||
Sut = default;
|
||||
}
|
||||
|
||||
ISutProvider ISutProvider.Create() => Create();
|
||||
public SutProvider<TSut> Create()
|
||||
{
|
||||
Sut = _fixture.Create<TSut>();
|
||||
return this;
|
||||
}
|
||||
|
||||
private bool DependencyIsSet(Type dependencyType, string parameterName = "")
|
||||
=> _dependencies.ContainsKey(dependencyType) && _dependencies[dependencyType].ContainsKey(parameterName);
|
||||
|
||||
private object GetDefault(Type type) => type.IsValueType ? Activator.CreateInstance(type) : null;
|
||||
|
||||
private class ConstructorParameterRelay<T> : ISpecimenBuilder
|
||||
{
|
||||
private readonly SutProvider<T> _sutProvider;
|
||||
private readonly IFixture _fixture;
|
||||
|
||||
public ConstructorParameterRelay(SutProvider<T> sutProvider, IFixture fixture)
|
||||
{
|
||||
_sutProvider = sutProvider;
|
||||
_fixture = fixture;
|
||||
return _sutProvider.GetDependency(parameterInfo.ParameterType, "");
|
||||
}
|
||||
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
if (!(request is ParameterInfo parameterInfo))
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
if (parameterInfo.Member.DeclaringType != typeof(T) ||
|
||||
parameterInfo.Member.MemberType != MemberTypes.Constructor)
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
if (_sutProvider.DependencyIsSet(parameterInfo.ParameterType, parameterInfo.Name))
|
||||
{
|
||||
return _sutProvider.GetDependency(parameterInfo.ParameterType, parameterInfo.Name);
|
||||
}
|
||||
// Return default type if set
|
||||
else if (_sutProvider.DependencyIsSet(parameterInfo.ParameterType, ""))
|
||||
{
|
||||
return _sutProvider.GetDependency(parameterInfo.ParameterType, "");
|
||||
}
|
||||
|
||||
|
||||
// This is the equivalent of _fixture.Create<parameterInfo.ParameterType>, but no overload for
|
||||
// Create(Type type) exists.
|
||||
var dependency = new SpecimenContext(_fixture).Resolve(new SeededRequest(parameterInfo.ParameterType,
|
||||
_sutProvider.GetDefault(parameterInfo.ParameterType)));
|
||||
_sutProvider.SetDependency(parameterInfo.ParameterType, dependency, parameterInfo.Name);
|
||||
return dependency;
|
||||
}
|
||||
// This is the equivalent of _fixture.Create<parameterInfo.ParameterType>, but no overload for
|
||||
// Create(Type type) exists.
|
||||
var dependency = new SpecimenContext(_fixture).Resolve(new SeededRequest(parameterInfo.ParameterType,
|
||||
_sutProvider.GetDefault(parameterInfo.ParameterType)));
|
||||
_sutProvider.SetDependency(parameterInfo.ParameterType, dependency, parameterInfo.Name);
|
||||
return dependency;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,33 @@
|
||||
using AutoFixture;
|
||||
using AutoFixture.Kernel;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes
|
||||
namespace Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
public class SutProviderCustomization : ICustomization, ISpecimenBuilder
|
||||
{
|
||||
public class SutProviderCustomization : ICustomization, ISpecimenBuilder
|
||||
private IFixture _fixture = null;
|
||||
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
{
|
||||
private IFixture _fixture = null;
|
||||
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
if (context == null)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
if (!(request is Type typeRequest))
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
if (!typeof(ISutProvider).IsAssignableFrom(typeRequest))
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
return ((ISutProvider)Activator.CreateInstance(typeRequest, _fixture)).Create();
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
if (!(request is Type typeRequest))
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
if (!typeof(ISutProvider).IsAssignableFrom(typeRequest))
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
fixture.Customizations.Add(this);
|
||||
}
|
||||
return ((ISutProvider)Activator.CreateInstance(typeRequest, _fixture)).Create();
|
||||
}
|
||||
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
fixture.Customizations.Add(this);
|
||||
}
|
||||
}
|
||||
|
@ -7,223 +7,222 @@ using Microsoft.AspNetCore.Http;
|
||||
using Xunit;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace Bit.Test.Common.Helpers
|
||||
namespace Bit.Test.Common.Helpers;
|
||||
|
||||
public static class AssertHelper
|
||||
{
|
||||
public static class AssertHelper
|
||||
public static void AssertPropertyEqual(object expected, object actual, params string[] excludedPropertyStrings)
|
||||
{
|
||||
public static void AssertPropertyEqual(object expected, object actual, params string[] excludedPropertyStrings)
|
||||
var relevantExcludedProperties = excludedPropertyStrings.Where(name => !name.Contains('.')).ToList();
|
||||
if (expected == null)
|
||||
{
|
||||
var relevantExcludedProperties = excludedPropertyStrings.Where(name => !name.Contains('.')).ToList();
|
||||
if (expected == null)
|
||||
{
|
||||
Assert.Null(actual);
|
||||
return;
|
||||
}
|
||||
|
||||
if (actual == null)
|
||||
{
|
||||
throw new Exception("Actual object is null but expected is not");
|
||||
}
|
||||
|
||||
foreach (var expectedPropInfo in expected.GetType().GetProperties().Where(pi => !relevantExcludedProperties.Contains(pi.Name)))
|
||||
{
|
||||
var actualPropInfo = actual.GetType().GetProperty(expectedPropInfo.Name);
|
||||
|
||||
if (actualPropInfo == null)
|
||||
{
|
||||
throw new Exception(string.Concat($"Expected actual object to contain a property named {expectedPropInfo.Name}, but it does not\n",
|
||||
$"Expected:\n{JsonSerializer.Serialize(expected, JsonHelpers.Indented)}\n",
|
||||
$"Actual:\n{JsonSerializer.Serialize(actual, JsonHelpers.Indented)}"));
|
||||
}
|
||||
|
||||
if (expectedPropInfo.PropertyType == typeof(string) || expectedPropInfo.PropertyType.IsValueType)
|
||||
{
|
||||
Assert.Equal(expectedPropInfo.GetValue(expected), actualPropInfo.GetValue(actual));
|
||||
}
|
||||
else if (expectedPropInfo.PropertyType == typeof(JsonDocument) && actualPropInfo.PropertyType == typeof(JsonDocument))
|
||||
{
|
||||
static string JsonDocString(PropertyInfo info, object obj) => JsonSerializer.Serialize(info.GetValue(obj));
|
||||
Assert.Equal(JsonDocString(expectedPropInfo, expected), JsonDocString(actualPropInfo, actual));
|
||||
}
|
||||
else
|
||||
{
|
||||
var prefix = $"{expectedPropInfo.PropertyType.Name}.";
|
||||
var nextExcludedProperties = excludedPropertyStrings.Where(name => name.StartsWith(prefix))
|
||||
.Select(name => name[prefix.Length..]).ToArray();
|
||||
AssertPropertyEqual(expectedPropInfo.GetValue(expected), actualPropInfo.GetValue(actual), nextExcludedProperties);
|
||||
}
|
||||
}
|
||||
Assert.Null(actual);
|
||||
return;
|
||||
}
|
||||
|
||||
private static Predicate<T> AssertPropertyEqualPredicate<T>(T expected, params string[] excludedPropertyStrings) => (actual) =>
|
||||
if (actual == null)
|
||||
{
|
||||
AssertPropertyEqual(expected, actual, excludedPropertyStrings);
|
||||
return true;
|
||||
};
|
||||
|
||||
public static Expression<Predicate<T>> AssertPropertyEqual<T>(T expected, params string[] excludedPropertyStrings) =>
|
||||
(T actual) => AssertPropertyEqualPredicate(expected, excludedPropertyStrings)(actual);
|
||||
|
||||
private static Predicate<IEnumerable<T>> AssertPropertyEqualPredicate<T>(IEnumerable<T> expected, params string[] excludedPropertyStrings) => (actual) =>
|
||||
{
|
||||
// IEnumerable.Zip doesn't account for different lengths, we need to check this ourselves
|
||||
if (actual.Count() != expected.Count())
|
||||
{
|
||||
throw new Exception(string.Concat($"Actual IEnumerable does not have the expected length.\n",
|
||||
$"Expected: {expected.Count()}\n",
|
||||
$"Actual: {actual.Count()}"));
|
||||
}
|
||||
|
||||
var elements = expected.Zip(actual);
|
||||
foreach (var (expectedEl, actualEl) in elements)
|
||||
{
|
||||
AssertPropertyEqual(expectedEl, actualEl, excludedPropertyStrings);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
public static Expression<Predicate<IEnumerable<T>>> AssertPropertyEqual<T>(IEnumerable<T> expected, params string[] excludedPropertyStrings) =>
|
||||
(actual) => AssertPropertyEqualPredicate(expected, excludedPropertyStrings)(actual);
|
||||
|
||||
private static Predicate<T> AssertEqualExpectedPredicate<T>(T expected) => (actual) =>
|
||||
{
|
||||
Assert.Equal(expected, actual);
|
||||
return true;
|
||||
};
|
||||
|
||||
public static Expression<Predicate<T>> AssertEqualExpected<T>(T expected) =>
|
||||
(T actual) => AssertEqualExpectedPredicate(expected)(actual);
|
||||
|
||||
public static JsonElement AssertJsonProperty(JsonElement element, string propertyName, JsonValueKind jsonValueKind)
|
||||
{
|
||||
if (!element.TryGetProperty(propertyName, out var subElement))
|
||||
{
|
||||
throw new XunitException($"Could not find property by name '{propertyName}'");
|
||||
}
|
||||
|
||||
Assert.Equal(jsonValueKind, subElement.ValueKind);
|
||||
return subElement;
|
||||
throw new Exception("Actual object is null but expected is not");
|
||||
}
|
||||
|
||||
public static void AssertEqualJson(JsonElement a, JsonElement b)
|
||||
foreach (var expectedPropInfo in expected.GetType().GetProperties().Where(pi => !relevantExcludedProperties.Contains(pi.Name)))
|
||||
{
|
||||
switch (a.ValueKind)
|
||||
var actualPropInfo = actual.GetType().GetProperty(expectedPropInfo.Name);
|
||||
|
||||
if (actualPropInfo == null)
|
||||
{
|
||||
case JsonValueKind.Array:
|
||||
Assert.Equal(JsonValueKind.Array, b.ValueKind);
|
||||
AssertEqualJsonArray(a, b);
|
||||
break;
|
||||
case JsonValueKind.Object:
|
||||
Assert.Equal(JsonValueKind.Object, b.ValueKind);
|
||||
AssertEqualJsonObject(a, b);
|
||||
break;
|
||||
case JsonValueKind.False:
|
||||
Assert.Equal(JsonValueKind.False, b.ValueKind);
|
||||
break;
|
||||
case JsonValueKind.True:
|
||||
Assert.Equal(JsonValueKind.True, b.ValueKind);
|
||||
break;
|
||||
case JsonValueKind.Number:
|
||||
Assert.Equal(JsonValueKind.Number, b.ValueKind);
|
||||
Assert.Equal(a.GetDouble(), b.GetDouble());
|
||||
break;
|
||||
case JsonValueKind.String:
|
||||
Assert.Equal(JsonValueKind.String, b.ValueKind);
|
||||
Assert.Equal(a.GetString(), b.GetString());
|
||||
break;
|
||||
case JsonValueKind.Null:
|
||||
Assert.Equal(JsonValueKind.Null, b.ValueKind);
|
||||
break;
|
||||
default:
|
||||
throw new XunitException($"Bad JsonValueKind '{a.ValueKind}'");
|
||||
throw new Exception(string.Concat($"Expected actual object to contain a property named {expectedPropInfo.Name}, but it does not\n",
|
||||
$"Expected:\n{JsonSerializer.Serialize(expected, JsonHelpers.Indented)}\n",
|
||||
$"Actual:\n{JsonSerializer.Serialize(actual, JsonHelpers.Indented)}"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void AssertEqualJsonObject(JsonElement a, JsonElement b)
|
||||
{
|
||||
Debug.Assert(a.ValueKind == JsonValueKind.Object && b.ValueKind == JsonValueKind.Object);
|
||||
|
||||
var aObjectEnumerator = a.EnumerateObject();
|
||||
var bObjectEnumerator = b.EnumerateObject();
|
||||
|
||||
while (true)
|
||||
if (expectedPropInfo.PropertyType == typeof(string) || expectedPropInfo.PropertyType.IsValueType)
|
||||
{
|
||||
var aCanMove = aObjectEnumerator.MoveNext();
|
||||
var bCanMove = bObjectEnumerator.MoveNext();
|
||||
|
||||
if (aCanMove)
|
||||
{
|
||||
Assert.True(bCanMove, $"a was able to enumerate over object '{a}' but b was NOT able to '{b}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.False(bCanMove, $"a was NOT able to enumerate over object '{a}' but b was able to '{b}'");
|
||||
}
|
||||
|
||||
if (aCanMove == false && bCanMove == false)
|
||||
{
|
||||
// They both can't continue to enumerate at the same time, that is valid
|
||||
break;
|
||||
}
|
||||
|
||||
var aProp = aObjectEnumerator.Current;
|
||||
var bProp = bObjectEnumerator.Current;
|
||||
|
||||
Assert.Equal(aProp.Name, bProp.Name);
|
||||
// Recursion!
|
||||
AssertEqualJson(aProp.Value, bProp.Value);
|
||||
Assert.Equal(expectedPropInfo.GetValue(expected), actualPropInfo.GetValue(actual));
|
||||
}
|
||||
}
|
||||
|
||||
private static void AssertEqualJsonArray(JsonElement a, JsonElement b)
|
||||
{
|
||||
Debug.Assert(a.ValueKind == JsonValueKind.Array && b.ValueKind == JsonValueKind.Array);
|
||||
|
||||
var aArrayEnumerator = a.EnumerateArray();
|
||||
var bArrayEnumerator = b.EnumerateArray();
|
||||
|
||||
while (true)
|
||||
else if (expectedPropInfo.PropertyType == typeof(JsonDocument) && actualPropInfo.PropertyType == typeof(JsonDocument))
|
||||
{
|
||||
var aCanMove = aArrayEnumerator.MoveNext();
|
||||
var bCanMove = bArrayEnumerator.MoveNext();
|
||||
|
||||
if (aCanMove)
|
||||
{
|
||||
Assert.True(bCanMove, $"a was able to enumerate over array '{a}' but b was NOT able to '{b}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.False(bCanMove, $"a was NOT able to enumerate over array '{a}' but b was able to '{b}'");
|
||||
}
|
||||
|
||||
if (aCanMove == false && bCanMove == false)
|
||||
{
|
||||
// They both can't continue to enumerate at the same time, that is valid
|
||||
break;
|
||||
}
|
||||
|
||||
var aElement = aArrayEnumerator.Current;
|
||||
var bElement = bArrayEnumerator.Current;
|
||||
|
||||
// Recursion!
|
||||
AssertEqualJson(aElement, bElement);
|
||||
static string JsonDocString(PropertyInfo info, object obj) => JsonSerializer.Serialize(info.GetValue(obj));
|
||||
Assert.Equal(JsonDocString(expectedPropInfo, expected), JsonDocString(actualPropInfo, actual));
|
||||
}
|
||||
else
|
||||
{
|
||||
var prefix = $"{expectedPropInfo.PropertyType.Name}.";
|
||||
var nextExcludedProperties = excludedPropertyStrings.Where(name => name.StartsWith(prefix))
|
||||
.Select(name => name[prefix.Length..]).ToArray();
|
||||
AssertPropertyEqual(expectedPropInfo.GetValue(expected), actualPropInfo.GetValue(actual), nextExcludedProperties);
|
||||
}
|
||||
}
|
||||
|
||||
public async static Task<T> AssertResponseTypeIs<T>(HttpContext context)
|
||||
{
|
||||
return await JsonSerializer.DeserializeAsync<T>(context.Response.Body);
|
||||
}
|
||||
|
||||
public static TimeSpan AssertRecent(DateTime dateTime, int skewSeconds = 2)
|
||||
=> AssertRecent(dateTime, TimeSpan.FromSeconds(skewSeconds));
|
||||
|
||||
public static TimeSpan AssertRecent(DateTime dateTime, TimeSpan skew)
|
||||
{
|
||||
var difference = DateTime.UtcNow - dateTime;
|
||||
Assert.True(difference < skew);
|
||||
return difference;
|
||||
}
|
||||
}
|
||||
|
||||
private static Predicate<T> AssertPropertyEqualPredicate<T>(T expected, params string[] excludedPropertyStrings) => (actual) =>
|
||||
{
|
||||
AssertPropertyEqual(expected, actual, excludedPropertyStrings);
|
||||
return true;
|
||||
};
|
||||
|
||||
public static Expression<Predicate<T>> AssertPropertyEqual<T>(T expected, params string[] excludedPropertyStrings) =>
|
||||
(T actual) => AssertPropertyEqualPredicate(expected, excludedPropertyStrings)(actual);
|
||||
|
||||
private static Predicate<IEnumerable<T>> AssertPropertyEqualPredicate<T>(IEnumerable<T> expected, params string[] excludedPropertyStrings) => (actual) =>
|
||||
{
|
||||
// IEnumerable.Zip doesn't account for different lengths, we need to check this ourselves
|
||||
if (actual.Count() != expected.Count())
|
||||
{
|
||||
throw new Exception(string.Concat($"Actual IEnumerable does not have the expected length.\n",
|
||||
$"Expected: {expected.Count()}\n",
|
||||
$"Actual: {actual.Count()}"));
|
||||
}
|
||||
|
||||
var elements = expected.Zip(actual);
|
||||
foreach (var (expectedEl, actualEl) in elements)
|
||||
{
|
||||
AssertPropertyEqual(expectedEl, actualEl, excludedPropertyStrings);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
public static Expression<Predicate<IEnumerable<T>>> AssertPropertyEqual<T>(IEnumerable<T> expected, params string[] excludedPropertyStrings) =>
|
||||
(actual) => AssertPropertyEqualPredicate(expected, excludedPropertyStrings)(actual);
|
||||
|
||||
private static Predicate<T> AssertEqualExpectedPredicate<T>(T expected) => (actual) =>
|
||||
{
|
||||
Assert.Equal(expected, actual);
|
||||
return true;
|
||||
};
|
||||
|
||||
public static Expression<Predicate<T>> AssertEqualExpected<T>(T expected) =>
|
||||
(T actual) => AssertEqualExpectedPredicate(expected)(actual);
|
||||
|
||||
public static JsonElement AssertJsonProperty(JsonElement element, string propertyName, JsonValueKind jsonValueKind)
|
||||
{
|
||||
if (!element.TryGetProperty(propertyName, out var subElement))
|
||||
{
|
||||
throw new XunitException($"Could not find property by name '{propertyName}'");
|
||||
}
|
||||
|
||||
Assert.Equal(jsonValueKind, subElement.ValueKind);
|
||||
return subElement;
|
||||
}
|
||||
|
||||
public static void AssertEqualJson(JsonElement a, JsonElement b)
|
||||
{
|
||||
switch (a.ValueKind)
|
||||
{
|
||||
case JsonValueKind.Array:
|
||||
Assert.Equal(JsonValueKind.Array, b.ValueKind);
|
||||
AssertEqualJsonArray(a, b);
|
||||
break;
|
||||
case JsonValueKind.Object:
|
||||
Assert.Equal(JsonValueKind.Object, b.ValueKind);
|
||||
AssertEqualJsonObject(a, b);
|
||||
break;
|
||||
case JsonValueKind.False:
|
||||
Assert.Equal(JsonValueKind.False, b.ValueKind);
|
||||
break;
|
||||
case JsonValueKind.True:
|
||||
Assert.Equal(JsonValueKind.True, b.ValueKind);
|
||||
break;
|
||||
case JsonValueKind.Number:
|
||||
Assert.Equal(JsonValueKind.Number, b.ValueKind);
|
||||
Assert.Equal(a.GetDouble(), b.GetDouble());
|
||||
break;
|
||||
case JsonValueKind.String:
|
||||
Assert.Equal(JsonValueKind.String, b.ValueKind);
|
||||
Assert.Equal(a.GetString(), b.GetString());
|
||||
break;
|
||||
case JsonValueKind.Null:
|
||||
Assert.Equal(JsonValueKind.Null, b.ValueKind);
|
||||
break;
|
||||
default:
|
||||
throw new XunitException($"Bad JsonValueKind '{a.ValueKind}'");
|
||||
}
|
||||
}
|
||||
|
||||
private static void AssertEqualJsonObject(JsonElement a, JsonElement b)
|
||||
{
|
||||
Debug.Assert(a.ValueKind == JsonValueKind.Object && b.ValueKind == JsonValueKind.Object);
|
||||
|
||||
var aObjectEnumerator = a.EnumerateObject();
|
||||
var bObjectEnumerator = b.EnumerateObject();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var aCanMove = aObjectEnumerator.MoveNext();
|
||||
var bCanMove = bObjectEnumerator.MoveNext();
|
||||
|
||||
if (aCanMove)
|
||||
{
|
||||
Assert.True(bCanMove, $"a was able to enumerate over object '{a}' but b was NOT able to '{b}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.False(bCanMove, $"a was NOT able to enumerate over object '{a}' but b was able to '{b}'");
|
||||
}
|
||||
|
||||
if (aCanMove == false && bCanMove == false)
|
||||
{
|
||||
// They both can't continue to enumerate at the same time, that is valid
|
||||
break;
|
||||
}
|
||||
|
||||
var aProp = aObjectEnumerator.Current;
|
||||
var bProp = bObjectEnumerator.Current;
|
||||
|
||||
Assert.Equal(aProp.Name, bProp.Name);
|
||||
// Recursion!
|
||||
AssertEqualJson(aProp.Value, bProp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AssertEqualJsonArray(JsonElement a, JsonElement b)
|
||||
{
|
||||
Debug.Assert(a.ValueKind == JsonValueKind.Array && b.ValueKind == JsonValueKind.Array);
|
||||
|
||||
var aArrayEnumerator = a.EnumerateArray();
|
||||
var bArrayEnumerator = b.EnumerateArray();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var aCanMove = aArrayEnumerator.MoveNext();
|
||||
var bCanMove = bArrayEnumerator.MoveNext();
|
||||
|
||||
if (aCanMove)
|
||||
{
|
||||
Assert.True(bCanMove, $"a was able to enumerate over array '{a}' but b was NOT able to '{b}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.False(bCanMove, $"a was NOT able to enumerate over array '{a}' but b was able to '{b}'");
|
||||
}
|
||||
|
||||
if (aCanMove == false && bCanMove == false)
|
||||
{
|
||||
// They both can't continue to enumerate at the same time, that is valid
|
||||
break;
|
||||
}
|
||||
|
||||
var aElement = aArrayEnumerator.Current;
|
||||
var bElement = bArrayEnumerator.Current;
|
||||
|
||||
// Recursion!
|
||||
AssertEqualJson(aElement, bElement);
|
||||
}
|
||||
}
|
||||
|
||||
public async static Task<T> AssertResponseTypeIs<T>(HttpContext context)
|
||||
{
|
||||
return await JsonSerializer.DeserializeAsync<T>(context.Response.Body);
|
||||
}
|
||||
|
||||
public static TimeSpan AssertRecent(DateTime dateTime, int skewSeconds = 2)
|
||||
=> AssertRecent(dateTime, TimeSpan.FromSeconds(skewSeconds));
|
||||
|
||||
public static TimeSpan AssertRecent(DateTime dateTime, TimeSpan skew)
|
||||
{
|
||||
var difference = DateTime.UtcNow - dateTime;
|
||||
Assert.True(difference < skew);
|
||||
return difference;
|
||||
}
|
||||
}
|
||||
|
@ -4,49 +4,48 @@ using AutoFixture.Kernel;
|
||||
using AutoFixture.Xunit2;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
namespace Bit.Test.Common.Helpers
|
||||
namespace Bit.Test.Common.Helpers;
|
||||
|
||||
public static class BitAutoDataAttributeHelpers
|
||||
{
|
||||
public static class BitAutoDataAttributeHelpers
|
||||
public static IEnumerable<object[]> GetData(MethodInfo testMethod, IFixture fixture, object[] fixedTestParameters)
|
||||
{
|
||||
public static IEnumerable<object[]> GetData(MethodInfo testMethod, IFixture fixture, object[] fixedTestParameters)
|
||||
var methodParameters = testMethod.GetParameters();
|
||||
var classCustomizations = testMethod.DeclaringType.GetCustomAttributes<BitCustomizeAttribute>().Select(attr => attr.GetCustomization());
|
||||
var methodCustomizations = testMethod.GetCustomAttributes<BitCustomizeAttribute>().Select(attr => attr.GetCustomization());
|
||||
|
||||
fixedTestParameters = fixedTestParameters ?? Array.Empty<object>();
|
||||
|
||||
fixture = ApplyCustomizations(ApplyCustomizations(fixture, classCustomizations), methodCustomizations);
|
||||
var missingParameters = methodParameters.Skip(fixedTestParameters.Length).Select(p => CustomizeAndCreate(p, fixture));
|
||||
|
||||
return new object[1][] { fixedTestParameters.Concat(missingParameters).ToArray() };
|
||||
}
|
||||
|
||||
public static object CustomizeAndCreate(ParameterInfo p, IFixture fixture)
|
||||
{
|
||||
var customizations = p.GetCustomAttributes(typeof(CustomizeAttribute), false)
|
||||
.OfType<CustomizeAttribute>()
|
||||
.Select(attr => attr.GetCustomization(p));
|
||||
|
||||
var context = new SpecimenContext(ApplyCustomizations(fixture, customizations));
|
||||
return context.Resolve(p);
|
||||
}
|
||||
|
||||
public static IFixture ApplyCustomizations(IFixture fixture, IEnumerable<ICustomization> customizations)
|
||||
{
|
||||
var newFixture = new Fixture();
|
||||
|
||||
foreach (var customization in fixture.Customizations.Reverse().Select(b => b.ToCustomization()))
|
||||
{
|
||||
var methodParameters = testMethod.GetParameters();
|
||||
var classCustomizations = testMethod.DeclaringType.GetCustomAttributes<BitCustomizeAttribute>().Select(attr => attr.GetCustomization());
|
||||
var methodCustomizations = testMethod.GetCustomAttributes<BitCustomizeAttribute>().Select(attr => attr.GetCustomization());
|
||||
|
||||
fixedTestParameters = fixedTestParameters ?? Array.Empty<object>();
|
||||
|
||||
fixture = ApplyCustomizations(ApplyCustomizations(fixture, classCustomizations), methodCustomizations);
|
||||
var missingParameters = methodParameters.Skip(fixedTestParameters.Length).Select(p => CustomizeAndCreate(p, fixture));
|
||||
|
||||
return new object[1][] { fixedTestParameters.Concat(missingParameters).ToArray() };
|
||||
newFixture.Customize(customization);
|
||||
}
|
||||
|
||||
public static object CustomizeAndCreate(ParameterInfo p, IFixture fixture)
|
||||
foreach (var customization in customizations)
|
||||
{
|
||||
var customizations = p.GetCustomAttributes(typeof(CustomizeAttribute), false)
|
||||
.OfType<CustomizeAttribute>()
|
||||
.Select(attr => attr.GetCustomization(p));
|
||||
|
||||
var context = new SpecimenContext(ApplyCustomizations(fixture, customizations));
|
||||
return context.Resolve(p);
|
||||
newFixture.Customize(customization);
|
||||
}
|
||||
|
||||
public static IFixture ApplyCustomizations(IFixture fixture, IEnumerable<ICustomization> customizations)
|
||||
{
|
||||
var newFixture = new Fixture();
|
||||
|
||||
foreach (var customization in fixture.Customizations.Reverse().Select(b => b.ToCustomization()))
|
||||
{
|
||||
newFixture.Customize(customization);
|
||||
}
|
||||
|
||||
foreach (var customization in customizations)
|
||||
{
|
||||
newFixture.Customize(customization);
|
||||
}
|
||||
|
||||
return newFixture;
|
||||
}
|
||||
return newFixture;
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +1,44 @@
|
||||
namespace Bit.Test.Common.Helpers
|
||||
namespace Bit.Test.Common.Helpers;
|
||||
|
||||
public static class TestCaseHelper
|
||||
{
|
||||
public static class TestCaseHelper
|
||||
public static IEnumerable<IEnumerable<T>> GetCombinations<T>(params T[] items)
|
||||
{
|
||||
public static IEnumerable<IEnumerable<T>> GetCombinations<T>(params T[] items)
|
||||
var count = Math.Pow(2, items.Length);
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var count = Math.Pow(2, items.Length);
|
||||
for (var i = 0; i < count; i++)
|
||||
var str = Convert.ToString(i, 2).PadLeft(items.Length, '0');
|
||||
List<T> combination = new();
|
||||
for (var j = 0; j < str.Length; j++)
|
||||
{
|
||||
var str = Convert.ToString(i, 2).PadLeft(items.Length, '0');
|
||||
List<T> combination = new();
|
||||
for (var j = 0; j < str.Length; j++)
|
||||
if (str[j] == '1')
|
||||
{
|
||||
if (str[j] == '1')
|
||||
{
|
||||
combination.Add(items[j]);
|
||||
}
|
||||
combination.Add(items[j]);
|
||||
}
|
||||
yield return combination;
|
||||
}
|
||||
yield return combination;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<IEnumerable<object>> GetCombinationsOfMultipleLists(params IEnumerable<object>[] optionLists)
|
||||
{
|
||||
if (!optionLists.Any())
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
public static IEnumerable<IEnumerable<object>> GetCombinationsOfMultipleLists(params IEnumerable<object>[] optionLists)
|
||||
foreach (var item in optionLists.First())
|
||||
{
|
||||
if (!optionLists.Any())
|
||||
var itemArray = new[] { item };
|
||||
|
||||
if (optionLists.Length == 1)
|
||||
{
|
||||
yield break;
|
||||
yield return itemArray;
|
||||
}
|
||||
|
||||
foreach (var item in optionLists.First())
|
||||
foreach (var nextCombination in GetCombinationsOfMultipleLists(optionLists.Skip(1).ToArray()))
|
||||
{
|
||||
var itemArray = new[] { item };
|
||||
|
||||
if (optionLists.Length == 1)
|
||||
{
|
||||
yield return itemArray;
|
||||
}
|
||||
|
||||
foreach (var nextCombination in GetCombinationsOfMultipleLists(optionLists.Skip(1).ToArray()))
|
||||
{
|
||||
yield return itemArray.Concat(nextCombination);
|
||||
}
|
||||
yield return itemArray.Concat(nextCombination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +1,50 @@
|
||||
using Bit.Test.Common.Helpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Test.Common.Test
|
||||
namespace Bit.Test.Common.Test;
|
||||
|
||||
public class TestCaseHelperTests
|
||||
{
|
||||
public class TestCaseHelperTests
|
||||
[Fact]
|
||||
public void GetCombinations_EmptyList()
|
||||
{
|
||||
[Fact]
|
||||
public void GetCombinations_EmptyList()
|
||||
{
|
||||
Assert.Equal(new[] { Array.Empty<int>() }, TestCaseHelper.GetCombinations(Array.Empty<int>()).ToArray());
|
||||
}
|
||||
Assert.Equal(new[] { Array.Empty<int>() }, TestCaseHelper.GetCombinations(Array.Empty<int>()).ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCombinations_OneItemList()
|
||||
{
|
||||
Assert.Equal(new[] { Array.Empty<int>(), new[] { 1 } }, TestCaseHelper.GetCombinations(1));
|
||||
}
|
||||
[Fact]
|
||||
public void GetCombinations_OneItemList()
|
||||
{
|
||||
Assert.Equal(new[] { Array.Empty<int>(), new[] { 1 } }, TestCaseHelper.GetCombinations(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCombinations_TwoItemList()
|
||||
{
|
||||
Assert.Equal(new[] { Array.Empty<int>(), new[] { 2 }, new[] { 1 }, new[] { 1, 2 } }, TestCaseHelper.GetCombinations(1, 2));
|
||||
}
|
||||
[Fact]
|
||||
public void GetCombinations_TwoItemList()
|
||||
{
|
||||
Assert.Equal(new[] { Array.Empty<int>(), new[] { 2 }, new[] { 1 }, new[] { 1, 2 } }, TestCaseHelper.GetCombinations(1, 2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCombinationsOfMultipleLists_OneOne()
|
||||
{
|
||||
Assert.Equal(new[] { new object[] { 1, "1" } }, TestCaseHelper.GetCombinationsOfMultipleLists(new object[] { 1 }, new object[] { "1" }));
|
||||
}
|
||||
[Fact]
|
||||
public void GetCombinationsOfMultipleLists_OneOne()
|
||||
{
|
||||
Assert.Equal(new[] { new object[] { 1, "1" } }, TestCaseHelper.GetCombinationsOfMultipleLists(new object[] { 1 }, new object[] { "1" }));
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void GetCombinationsOfMultipleLists_OneTwo()
|
||||
{
|
||||
Assert.Equal(new[] { new object[] { 1, "1" }, new object[] { 1, "2" } }, TestCaseHelper.GetCombinationsOfMultipleLists(new object[] { 1 }, new object[] { "1", "2" }));
|
||||
}
|
||||
[Fact]
|
||||
public void GetCombinationsOfMultipleLists_OneTwo()
|
||||
{
|
||||
Assert.Equal(new[] { new object[] { 1, "1" }, new object[] { 1, "2" } }, TestCaseHelper.GetCombinationsOfMultipleLists(new object[] { 1 }, new object[] { "1", "2" }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCombinationsOfMultipleLists_TwoOne()
|
||||
{
|
||||
Assert.Equal(new[] { new object[] { 1, "1" }, new object[] { 2, "1" } }, TestCaseHelper.GetCombinationsOfMultipleLists(new object[] { 1, 2 }, new object[] { "1" }));
|
||||
}
|
||||
[Fact]
|
||||
public void GetCombinationsOfMultipleLists_TwoOne()
|
||||
{
|
||||
Assert.Equal(new[] { new object[] { 1, "1" }, new object[] { 2, "1" } }, TestCaseHelper.GetCombinationsOfMultipleLists(new object[] { 1, 2 }, new object[] { "1" }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCombinationsOfMultipleLists_TwoTwo()
|
||||
{
|
||||
Assert.Equal(new[] { new object[] { 1, "1" }, new object[] { 1, "2" }, new object[] { 2, "1" }, new object[] { 2, "2" } }, TestCaseHelper.GetCombinationsOfMultipleLists(new object[] { 1, 2 }, new object[] { "1", "2" }));
|
||||
}
|
||||
[Fact]
|
||||
public void GetCombinationsOfMultipleLists_TwoTwo()
|
||||
{
|
||||
Assert.Equal(new[] { new object[] { 1, "1" }, new object[] { 1, "2" }, new object[] { 2, "1" }, new object[] { 2, "2" } }, TestCaseHelper.GetCombinationsOfMultipleLists(new object[] { 1, 2 }, new object[] { "1", "2" }));
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
namespace Bit.Core.Test.AutoFixture.Attributes
|
||||
namespace Bit.Core.Test.AutoFixture.Attributes;
|
||||
|
||||
public sealed class CiSkippedTheory : Xunit.TheoryAttribute
|
||||
{
|
||||
public sealed class CiSkippedTheory : Xunit.TheoryAttribute
|
||||
private static bool IsGithubActions() => Environment.GetEnvironmentVariable("CI") != null;
|
||||
public CiSkippedTheory()
|
||||
{
|
||||
private static bool IsGithubActions() => Environment.GetEnvironmentVariable("CI") != null;
|
||||
public CiSkippedTheory()
|
||||
if (IsGithubActions())
|
||||
{
|
||||
if (IsGithubActions())
|
||||
{
|
||||
Skip = "Ignore during CI builds";
|
||||
}
|
||||
Skip = "Ignore during CI builds";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,32 +2,31 @@
|
||||
using AutoFixture.Dsl;
|
||||
using Bit.Core.Models.Data;
|
||||
|
||||
namespace Bit.Core.Test.AutoFixture.CipherAttachmentMetaData
|
||||
namespace Bit.Core.Test.AutoFixture.CipherAttachmentMetaData;
|
||||
|
||||
public class MetaData : ICustomization
|
||||
{
|
||||
public class MetaData : ICustomization
|
||||
protected virtual IPostprocessComposer<CipherAttachment.MetaData> ComposerAction(IFixture fixture,
|
||||
ICustomizationComposer<CipherAttachment.MetaData> composer)
|
||||
{
|
||||
protected virtual IPostprocessComposer<CipherAttachment.MetaData> ComposerAction(IFixture fixture,
|
||||
ICustomizationComposer<CipherAttachment.MetaData> composer)
|
||||
{
|
||||
return composer.With(d => d.Size, fixture.Create<long>());
|
||||
}
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<CipherAttachment.MetaData>(composer => ComposerAction(fixture, composer));
|
||||
}
|
||||
return composer.With(d => d.Size, fixture.Create<long>());
|
||||
}
|
||||
|
||||
public class MetaDataWithoutContainer : MetaData
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
protected override IPostprocessComposer<CipherAttachment.MetaData> ComposerAction(IFixture fixture,
|
||||
ICustomizationComposer<CipherAttachment.MetaData> composer) =>
|
||||
base.ComposerAction(fixture, composer).With(d => d.ContainerName, (string)null);
|
||||
}
|
||||
|
||||
public class MetaDataWithoutKey : MetaDataWithoutContainer
|
||||
{
|
||||
protected override IPostprocessComposer<CipherAttachment.MetaData> ComposerAction(IFixture fixture,
|
||||
ICustomizationComposer<CipherAttachment.MetaData> composer) =>
|
||||
base.ComposerAction(fixture, composer).Without(d => d.Key);
|
||||
fixture.Customize<CipherAttachment.MetaData>(composer => ComposerAction(fixture, composer));
|
||||
}
|
||||
}
|
||||
|
||||
public class MetaDataWithoutContainer : MetaData
|
||||
{
|
||||
protected override IPostprocessComposer<CipherAttachment.MetaData> ComposerAction(IFixture fixture,
|
||||
ICustomizationComposer<CipherAttachment.MetaData> composer) =>
|
||||
base.ComposerAction(fixture, composer).With(d => d.ContainerName, (string)null);
|
||||
}
|
||||
|
||||
public class MetaDataWithoutKey : MetaDataWithoutContainer
|
||||
{
|
||||
protected override IPostprocessComposer<CipherAttachment.MetaData> ComposerAction(IFixture fixture,
|
||||
ICustomizationComposer<CipherAttachment.MetaData> composer) =>
|
||||
base.ComposerAction(fixture, composer).Without(d => d.Key);
|
||||
}
|
||||
|
@ -3,67 +3,66 @@ using Bit.Core.Entities;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Core.Models.Data;
|
||||
|
||||
namespace Bit.Core.Test.AutoFixture.CipherFixtures
|
||||
namespace Bit.Core.Test.AutoFixture.CipherFixtures;
|
||||
|
||||
internal class OrganizationCipher : ICustomization
|
||||
{
|
||||
internal class OrganizationCipher : ICustomization
|
||||
public Guid? OrganizationId { get; set; }
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
public Guid? OrganizationId { get; set; }
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<Cipher>(composer => composer
|
||||
.With(c => c.OrganizationId, OrganizationId ?? Guid.NewGuid())
|
||||
.Without(c => c.UserId));
|
||||
fixture.Customize<CipherDetails>(composer => composer
|
||||
.With(c => c.OrganizationId, Guid.NewGuid())
|
||||
.Without(c => c.UserId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class UserCipher : ICustomization
|
||||
{
|
||||
public Guid? UserId { get; set; }
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<Cipher>(composer => composer
|
||||
.With(c => c.UserId, UserId ?? Guid.NewGuid())
|
||||
.Without(c => c.OrganizationId));
|
||||
fixture.Customize<CipherDetails>(composer => composer
|
||||
.With(c => c.UserId, Guid.NewGuid())
|
||||
.Without(c => c.OrganizationId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class UserCipherAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public UserCipherAutoDataAttribute(string userId = null) : base(new SutProviderCustomization(),
|
||||
new UserCipher { UserId = userId == null ? (Guid?)null : new Guid(userId) })
|
||||
{ }
|
||||
}
|
||||
internal class InlineUserCipherAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineUserCipherAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
|
||||
typeof(UserCipher) }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineKnownUserCipherAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineKnownUserCipherAutoDataAttribute(string userId, params object[] values) : base(new ICustomization[]
|
||||
{ new SutProviderCustomization(), new UserCipher { UserId = new Guid(userId) } }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class OrganizationCipherAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public OrganizationCipherAutoDataAttribute(string organizationId = null) : base(new SutProviderCustomization(),
|
||||
new OrganizationCipher { OrganizationId = organizationId == null ? (Guid?)null : new Guid(organizationId) })
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineOrganizationCipherAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineOrganizationCipherAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
|
||||
typeof(OrganizationCipher) }, values)
|
||||
{ }
|
||||
fixture.Customize<Cipher>(composer => composer
|
||||
.With(c => c.OrganizationId, OrganizationId ?? Guid.NewGuid())
|
||||
.Without(c => c.UserId));
|
||||
fixture.Customize<CipherDetails>(composer => composer
|
||||
.With(c => c.OrganizationId, Guid.NewGuid())
|
||||
.Without(c => c.UserId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class UserCipher : ICustomization
|
||||
{
|
||||
public Guid? UserId { get; set; }
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<Cipher>(composer => composer
|
||||
.With(c => c.UserId, UserId ?? Guid.NewGuid())
|
||||
.Without(c => c.OrganizationId));
|
||||
fixture.Customize<CipherDetails>(composer => composer
|
||||
.With(c => c.UserId, Guid.NewGuid())
|
||||
.Without(c => c.OrganizationId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class UserCipherAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public UserCipherAutoDataAttribute(string userId = null) : base(new SutProviderCustomization(),
|
||||
new UserCipher { UserId = userId == null ? (Guid?)null : new Guid(userId) })
|
||||
{ }
|
||||
}
|
||||
internal class InlineUserCipherAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineUserCipherAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
|
||||
typeof(UserCipher) }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineKnownUserCipherAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineKnownUserCipherAutoDataAttribute(string userId, params object[] values) : base(new ICustomization[]
|
||||
{ new SutProviderCustomization(), new UserCipher { UserId = new Guid(userId) } }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class OrganizationCipherAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public OrganizationCipherAutoDataAttribute(string organizationId = null) : base(new SutProviderCustomization(),
|
||||
new OrganizationCipher { OrganizationId = organizationId == null ? (Guid?)null : new Guid(organizationId) })
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineOrganizationCipherAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineOrganizationCipherAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
|
||||
typeof(OrganizationCipher) }, values)
|
||||
{ }
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
using Bit.Core.Test.AutoFixture.OrganizationFixtures;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
namespace Bit.Core.Test.AutoFixture.CollectionFixtures
|
||||
namespace Bit.Core.Test.AutoFixture.CollectionFixtures;
|
||||
|
||||
internal class CollectionAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
internal class CollectionAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public CollectionAutoDataAttribute() : base(new SutProviderCustomization(), new OrganizationCustomization())
|
||||
{ }
|
||||
}
|
||||
public CollectionAutoDataAttribute() : base(new SutProviderCustomization(), new OrganizationCustomization())
|
||||
{ }
|
||||
}
|
||||
|
@ -3,36 +3,35 @@ using AutoFixture.Kernel;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
|
||||
namespace Bit.Core.Test.AutoFixture.CurrentContextFixtures
|
||||
namespace Bit.Core.Test.AutoFixture.CurrentContextFixtures;
|
||||
|
||||
internal class CurrentContext : ICustomization
|
||||
{
|
||||
internal class CurrentContext : ICustomization
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customizations.Add(new CurrentContextBuilder());
|
||||
}
|
||||
}
|
||||
|
||||
internal class CurrentContextBuilder : ISpecimenBuilder
|
||||
{
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
if (!(request is Type typeRequest))
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
if (typeof(ICurrentContext) != typeRequest)
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
var obj = new Fixture().WithAutoNSubstitutions().Create<ICurrentContext>();
|
||||
obj.Organizations = context.Create<List<CurrentContentOrganization>>();
|
||||
return obj;
|
||||
}
|
||||
fixture.Customizations.Add(new CurrentContextBuilder());
|
||||
}
|
||||
}
|
||||
|
||||
internal class CurrentContextBuilder : ISpecimenBuilder
|
||||
{
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
if (!(request is Type typeRequest))
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
if (typeof(ICurrentContext) != typeRequest)
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
var obj = new Fixture().WithAutoNSubstitutions().Create<ICurrentContext>();
|
||||
obj.Organizations = context.Create<List<CurrentContentOrganization>>();
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
@ -4,29 +4,28 @@ using AutoFixture.Kernel;
|
||||
using AutoFixture.Xunit2;
|
||||
using Bit.Core.Test.Helpers.Factories;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture
|
||||
namespace Bit.Test.Common.AutoFixture;
|
||||
|
||||
public class GlobalSettingsBuilder : ISpecimenBuilder
|
||||
{
|
||||
public class GlobalSettingsBuilder : ISpecimenBuilder
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
{
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
if (context == null)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var pi = request as ParameterInfo;
|
||||
var fixture = new Fixture();
|
||||
|
||||
if (pi == null || pi.ParameterType != typeof(Bit.Core.Settings.GlobalSettings))
|
||||
return new NoSpecimen();
|
||||
|
||||
return GlobalSettingsFactory.GlobalSettings;
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
}
|
||||
|
||||
public class GlobalSettingsCustomizeAttribute : CustomizeAttribute
|
||||
{
|
||||
public override ICustomization GetCustomization(ParameterInfo parameter) => new GlobalSettings();
|
||||
var pi = request as ParameterInfo;
|
||||
var fixture = new Fixture();
|
||||
|
||||
if (pi == null || pi.ParameterType != typeof(Bit.Core.Settings.GlobalSettings))
|
||||
return new NoSpecimen();
|
||||
|
||||
return GlobalSettingsFactory.GlobalSettings;
|
||||
}
|
||||
}
|
||||
|
||||
public class GlobalSettingsCustomizeAttribute : CustomizeAttribute
|
||||
{
|
||||
public override ICustomization GetCustomization(ParameterInfo parameter) => new GlobalSettings();
|
||||
}
|
||||
|
@ -1,19 +1,18 @@
|
||||
using Bit.Core.Test.AutoFixture.OrganizationFixtures;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
namespace Bit.Core.Test.AutoFixture.GroupFixtures
|
||||
{
|
||||
internal class GroupOrganizationAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public GroupOrganizationAutoDataAttribute() : base(
|
||||
new SutProviderCustomization(), new OrganizationCustomization { UseGroups = true })
|
||||
{ }
|
||||
}
|
||||
namespace Bit.Core.Test.AutoFixture.GroupFixtures;
|
||||
|
||||
internal class GroupOrganizationNotUseGroupsAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public GroupOrganizationNotUseGroupsAutoDataAttribute() : base(
|
||||
new SutProviderCustomization(), new OrganizationCustomization { UseGroups = false })
|
||||
{ }
|
||||
}
|
||||
internal class GroupOrganizationAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public GroupOrganizationAutoDataAttribute() : base(
|
||||
new SutProviderCustomization(), new OrganizationCustomization { UseGroups = true })
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class GroupOrganizationNotUseGroupsAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public GroupOrganizationNotUseGroupsAutoDataAttribute() : base(
|
||||
new SutProviderCustomization(), new OrganizationCustomization { UseGroups = false })
|
||||
{ }
|
||||
}
|
||||
|
@ -10,177 +10,176 @@ using Bit.Core.Utilities;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
namespace Bit.Core.Test.AutoFixture.OrganizationFixtures
|
||||
namespace Bit.Core.Test.AutoFixture.OrganizationFixtures;
|
||||
|
||||
public class OrganizationCustomization : ICustomization
|
||||
{
|
||||
public class OrganizationCustomization : ICustomization
|
||||
public bool UseGroups { get; set; }
|
||||
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
public bool UseGroups { get; set; }
|
||||
var organizationId = Guid.NewGuid();
|
||||
var maxConnections = (short)new Random().Next(10, short.MaxValue);
|
||||
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
var organizationId = Guid.NewGuid();
|
||||
var maxConnections = (short)new Random().Next(10, short.MaxValue);
|
||||
fixture.Customize<Organization>(composer => composer
|
||||
.With(o => o.Id, organizationId)
|
||||
.With(o => o.MaxCollections, maxConnections)
|
||||
.With(o => o.UseGroups, UseGroups));
|
||||
|
||||
fixture.Customize<Organization>(composer => composer
|
||||
.With(o => o.Id, organizationId)
|
||||
.With(o => o.MaxCollections, maxConnections)
|
||||
.With(o => o.UseGroups, UseGroups));
|
||||
fixture.Customize<Collection>(composer =>
|
||||
composer
|
||||
.With(c => c.OrganizationId, organizationId)
|
||||
.Without(o => o.CreationDate)
|
||||
.Without(o => o.RevisionDate));
|
||||
|
||||
fixture.Customize<Collection>(composer =>
|
||||
composer
|
||||
.With(c => c.OrganizationId, organizationId)
|
||||
.Without(o => o.CreationDate)
|
||||
.Without(o => o.RevisionDate));
|
||||
|
||||
fixture.Customize<Group>(composer => composer.With(g => g.OrganizationId, organizationId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class OrganizationBuilder : 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(Organization))
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
var fixture = new Fixture();
|
||||
var providers = fixture.Create<Dictionary<TwoFactorProviderType, TwoFactorProvider>>();
|
||||
var organization = new Fixture().WithAutoNSubstitutions().Create<Organization>();
|
||||
organization.SetTwoFactorProviders(providers);
|
||||
return organization;
|
||||
}
|
||||
}
|
||||
|
||||
internal class PaidOrganization : ICustomization
|
||||
{
|
||||
public PlanType CheckedPlanType { get; set; }
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
var validUpgradePlans = StaticStore.Plans.Where(p => p.Type != PlanType.Free && !p.Disabled).Select(p => p.Type).ToList();
|
||||
var lowestActivePaidPlan = validUpgradePlans.First();
|
||||
CheckedPlanType = CheckedPlanType.Equals(PlanType.Free) ? lowestActivePaidPlan : CheckedPlanType;
|
||||
validUpgradePlans.Remove(lowestActivePaidPlan);
|
||||
fixture.Customize<Organization>(composer => composer
|
||||
.With(o => o.PlanType, CheckedPlanType));
|
||||
fixture.Customize<OrganizationUpgrade>(composer => composer
|
||||
.With(ou => ou.Plan, validUpgradePlans.First()));
|
||||
}
|
||||
}
|
||||
|
||||
internal class FreeOrganization : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<Organization>(composer => composer
|
||||
.With(o => o.PlanType, PlanType.Free));
|
||||
}
|
||||
}
|
||||
|
||||
internal class FreeOrganizationUpgrade : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<Organization>(composer => composer
|
||||
.With(o => o.PlanType, PlanType.Free));
|
||||
|
||||
var plansToIgnore = new List<PlanType> { PlanType.Free, PlanType.Custom };
|
||||
var selectedPlan = StaticStore.Plans.Last(p => !plansToIgnore.Contains(p.Type) && !p.Disabled);
|
||||
|
||||
fixture.Customize<OrganizationUpgrade>(composer => composer
|
||||
.With(ou => ou.Plan, selectedPlan.Type)
|
||||
.With(ou => ou.PremiumAccessAddon, selectedPlan.HasPremiumAccessOption));
|
||||
fixture.Customize<Organization>(composer => composer
|
||||
.Without(o => o.GatewaySubscriptionId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class OrganizationInvite : ICustomization
|
||||
{
|
||||
public OrganizationUserType InviteeUserType { get; set; }
|
||||
public OrganizationUserType InvitorUserType { get; set; }
|
||||
public string PermissionsBlob { get; set; }
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
var organizationId = new Guid();
|
||||
PermissionsBlob = PermissionsBlob ?? JsonSerializer.Serialize(new Permissions(), new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
});
|
||||
fixture.Customize<Organization>(composer => composer
|
||||
.With(o => o.Id, organizationId)
|
||||
.With(o => o.Seats, (short)100));
|
||||
fixture.Customize<OrganizationUser>(composer => composer
|
||||
.With(ou => ou.OrganizationId, organizationId)
|
||||
.With(ou => ou.Type, InvitorUserType)
|
||||
.With(ou => ou.Permissions, PermissionsBlob));
|
||||
fixture.Customize<OrganizationUserInvite>(composer => composer
|
||||
.With(oi => oi.Type, InviteeUserType));
|
||||
}
|
||||
}
|
||||
|
||||
internal class PaidOrganizationAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public PaidOrganizationAutoDataAttribute(PlanType planType) : base(new SutProviderCustomization(),
|
||||
new PaidOrganization { CheckedPlanType = planType })
|
||||
{ }
|
||||
public PaidOrganizationAutoDataAttribute(int planType = 0) : this((PlanType)planType) { }
|
||||
}
|
||||
|
||||
internal class InlinePaidOrganizationAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlinePaidOrganizationAutoDataAttribute(PlanType planType, object[] values) : base(
|
||||
new ICustomization[] { new SutProviderCustomization(), new PaidOrganization { CheckedPlanType = planType } }, values)
|
||||
{ }
|
||||
|
||||
public InlinePaidOrganizationAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
|
||||
typeof(PaidOrganization) }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineFreeOrganizationAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineFreeOrganizationAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
|
||||
typeof(FreeOrganization) }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class FreeOrganizationUpgradeAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public FreeOrganizationUpgradeAutoDataAttribute() : base(new SutProviderCustomization(), new FreeOrganizationUpgrade())
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineFreeOrganizationUpgradeAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineFreeOrganizationUpgradeAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
|
||||
typeof(FreeOrganizationUpgrade) }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class OrganizationInviteAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public OrganizationInviteAutoDataAttribute(int inviteeUserType = 0, int invitorUserType = 0, string permissionsBlob = null) : base(new SutProviderCustomization(),
|
||||
new OrganizationInvite
|
||||
{
|
||||
InviteeUserType = (OrganizationUserType)inviteeUserType,
|
||||
InvitorUserType = (OrganizationUserType)invitorUserType,
|
||||
PermissionsBlob = permissionsBlob,
|
||||
})
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineOrganizationInviteAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineOrganizationInviteAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
|
||||
typeof(OrganizationInvite) }, values)
|
||||
{ }
|
||||
fixture.Customize<Group>(composer => composer.With(g => g.OrganizationId, organizationId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class OrganizationBuilder : 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(Organization))
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
var fixture = new Fixture();
|
||||
var providers = fixture.Create<Dictionary<TwoFactorProviderType, TwoFactorProvider>>();
|
||||
var organization = new Fixture().WithAutoNSubstitutions().Create<Organization>();
|
||||
organization.SetTwoFactorProviders(providers);
|
||||
return organization;
|
||||
}
|
||||
}
|
||||
|
||||
internal class PaidOrganization : ICustomization
|
||||
{
|
||||
public PlanType CheckedPlanType { get; set; }
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
var validUpgradePlans = StaticStore.Plans.Where(p => p.Type != PlanType.Free && !p.Disabled).Select(p => p.Type).ToList();
|
||||
var lowestActivePaidPlan = validUpgradePlans.First();
|
||||
CheckedPlanType = CheckedPlanType.Equals(PlanType.Free) ? lowestActivePaidPlan : CheckedPlanType;
|
||||
validUpgradePlans.Remove(lowestActivePaidPlan);
|
||||
fixture.Customize<Organization>(composer => composer
|
||||
.With(o => o.PlanType, CheckedPlanType));
|
||||
fixture.Customize<OrganizationUpgrade>(composer => composer
|
||||
.With(ou => ou.Plan, validUpgradePlans.First()));
|
||||
}
|
||||
}
|
||||
|
||||
internal class FreeOrganization : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<Organization>(composer => composer
|
||||
.With(o => o.PlanType, PlanType.Free));
|
||||
}
|
||||
}
|
||||
|
||||
internal class FreeOrganizationUpgrade : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<Organization>(composer => composer
|
||||
.With(o => o.PlanType, PlanType.Free));
|
||||
|
||||
var plansToIgnore = new List<PlanType> { PlanType.Free, PlanType.Custom };
|
||||
var selectedPlan = StaticStore.Plans.Last(p => !plansToIgnore.Contains(p.Type) && !p.Disabled);
|
||||
|
||||
fixture.Customize<OrganizationUpgrade>(composer => composer
|
||||
.With(ou => ou.Plan, selectedPlan.Type)
|
||||
.With(ou => ou.PremiumAccessAddon, selectedPlan.HasPremiumAccessOption));
|
||||
fixture.Customize<Organization>(composer => composer
|
||||
.Without(o => o.GatewaySubscriptionId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class OrganizationInvite : ICustomization
|
||||
{
|
||||
public OrganizationUserType InviteeUserType { get; set; }
|
||||
public OrganizationUserType InvitorUserType { get; set; }
|
||||
public string PermissionsBlob { get; set; }
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
var organizationId = new Guid();
|
||||
PermissionsBlob = PermissionsBlob ?? JsonSerializer.Serialize(new Permissions(), new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
});
|
||||
fixture.Customize<Organization>(composer => composer
|
||||
.With(o => o.Id, organizationId)
|
||||
.With(o => o.Seats, (short)100));
|
||||
fixture.Customize<OrganizationUser>(composer => composer
|
||||
.With(ou => ou.OrganizationId, organizationId)
|
||||
.With(ou => ou.Type, InvitorUserType)
|
||||
.With(ou => ou.Permissions, PermissionsBlob));
|
||||
fixture.Customize<OrganizationUserInvite>(composer => composer
|
||||
.With(oi => oi.Type, InviteeUserType));
|
||||
}
|
||||
}
|
||||
|
||||
internal class PaidOrganizationAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public PaidOrganizationAutoDataAttribute(PlanType planType) : base(new SutProviderCustomization(),
|
||||
new PaidOrganization { CheckedPlanType = planType })
|
||||
{ }
|
||||
public PaidOrganizationAutoDataAttribute(int planType = 0) : this((PlanType)planType) { }
|
||||
}
|
||||
|
||||
internal class InlinePaidOrganizationAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlinePaidOrganizationAutoDataAttribute(PlanType planType, object[] values) : base(
|
||||
new ICustomization[] { new SutProviderCustomization(), new PaidOrganization { CheckedPlanType = planType } }, values)
|
||||
{ }
|
||||
|
||||
public InlinePaidOrganizationAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
|
||||
typeof(PaidOrganization) }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineFreeOrganizationAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineFreeOrganizationAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
|
||||
typeof(FreeOrganization) }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class FreeOrganizationUpgradeAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public FreeOrganizationUpgradeAutoDataAttribute() : base(new SutProviderCustomization(), new FreeOrganizationUpgrade())
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineFreeOrganizationUpgradeAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineFreeOrganizationUpgradeAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
|
||||
typeof(FreeOrganizationUpgrade) }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class OrganizationInviteAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public OrganizationInviteAutoDataAttribute(int inviteeUserType = 0, int invitorUserType = 0, string permissionsBlob = null) : base(new SutProviderCustomization(),
|
||||
new OrganizationInvite
|
||||
{
|
||||
InviteeUserType = (OrganizationUserType)inviteeUserType,
|
||||
InvitorUserType = (OrganizationUserType)invitorUserType,
|
||||
PermissionsBlob = permissionsBlob,
|
||||
})
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineOrganizationInviteAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineOrganizationInviteAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
|
||||
typeof(OrganizationInvite) }, values)
|
||||
{ }
|
||||
}
|
||||
|
@ -2,18 +2,17 @@
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
namespace Bit.Core.Test.AutoFixture
|
||||
namespace Bit.Core.Test.AutoFixture;
|
||||
|
||||
public class OrganizationLicenseCustomizeAttribute : BitCustomizeAttribute
|
||||
{
|
||||
public class OrganizationLicenseCustomizeAttribute : BitCustomizeAttribute
|
||||
public override ICustomization GetCustomization() => new OrganizationLicenseCustomization();
|
||||
}
|
||||
public class OrganizationLicenseCustomization : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
public override ICustomization GetCustomization() => new OrganizationLicenseCustomization();
|
||||
}
|
||||
public class OrganizationLicenseCustomization : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<OrganizationLicense>(composer => composer
|
||||
.With(o => o.Signature, Guid.NewGuid().ToString().Replace('-', '+')));
|
||||
}
|
||||
fixture.Customize<OrganizationLicense>(composer => composer
|
||||
.With(o => o.Signature, Guid.NewGuid().ToString().Replace('-', '+')));
|
||||
}
|
||||
}
|
||||
|
@ -2,32 +2,31 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
namespace Bit.Core.Test.AutoFixture.OrganizationSponsorshipFixtures
|
||||
namespace Bit.Core.Test.AutoFixture.OrganizationSponsorshipFixtures;
|
||||
|
||||
public class OrganizationSponsorshipCustomizeAttribute : BitCustomizeAttribute
|
||||
{
|
||||
public class OrganizationSponsorshipCustomizeAttribute : BitCustomizeAttribute
|
||||
{
|
||||
public bool ToDelete = false;
|
||||
public override ICustomization GetCustomization() => ToDelete ?
|
||||
new ToDeleteOrganizationSponsorship() :
|
||||
new ValidOrganizationSponsorship();
|
||||
}
|
||||
public bool ToDelete = false;
|
||||
public override ICustomization GetCustomization() => ToDelete ?
|
||||
new ToDeleteOrganizationSponsorship() :
|
||||
new ValidOrganizationSponsorship();
|
||||
}
|
||||
|
||||
public class ValidOrganizationSponsorship : ICustomization
|
||||
public class ValidOrganizationSponsorship : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<OrganizationSponsorship>(composer => composer
|
||||
.With(s => s.ToDelete, false)
|
||||
.With(s => s.LastSyncDate, DateTime.UtcNow.AddDays(new Random().Next(-90, 0))));
|
||||
}
|
||||
}
|
||||
|
||||
public class ToDeleteOrganizationSponsorship : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<OrganizationSponsorship>(composer => composer
|
||||
.With(s => s.ToDelete, true));
|
||||
}
|
||||
fixture.Customize<OrganizationSponsorship>(composer => composer
|
||||
.With(s => s.ToDelete, false)
|
||||
.With(s => s.LastSyncDate, DateTime.UtcNow.AddDays(new Random().Next(-90, 0))));
|
||||
}
|
||||
}
|
||||
|
||||
public class ToDeleteOrganizationSponsorship : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<OrganizationSponsorship>(composer => composer
|
||||
.With(s => s.ToDelete, true));
|
||||
}
|
||||
}
|
||||
|
@ -4,43 +4,42 @@ using AutoFixture.Xunit2;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Test.AutoFixture.OrganizationUserFixtures
|
||||
namespace Bit.Core.Test.AutoFixture.OrganizationUserFixtures;
|
||||
|
||||
public class OrganizationUserCustomization : ICustomization
|
||||
{
|
||||
public class OrganizationUserCustomization : ICustomization
|
||||
public OrganizationUserStatusType Status { get; set; }
|
||||
public OrganizationUserType Type { get; set; }
|
||||
|
||||
public OrganizationUserCustomization(OrganizationUserStatusType status, OrganizationUserType type)
|
||||
{
|
||||
public OrganizationUserStatusType Status { get; set; }
|
||||
public OrganizationUserType Type { get; set; }
|
||||
|
||||
public OrganizationUserCustomization(OrganizationUserStatusType status, OrganizationUserType type)
|
||||
{
|
||||
Status = status;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<OrganizationUser>(composer => composer
|
||||
.With(o => o.Type, Type)
|
||||
.With(o => o.Status, Status));
|
||||
}
|
||||
Status = status;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public class OrganizationUserAttribute : CustomizeAttribute
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
private readonly OrganizationUserStatusType _status;
|
||||
private readonly OrganizationUserType _type;
|
||||
|
||||
public OrganizationUserAttribute(
|
||||
OrganizationUserStatusType status = OrganizationUserStatusType.Confirmed,
|
||||
OrganizationUserType type = OrganizationUserType.User)
|
||||
{
|
||||
_status = status;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public override ICustomization GetCustomization(ParameterInfo parameter)
|
||||
{
|
||||
return new OrganizationUserCustomization(_status, _type);
|
||||
}
|
||||
fixture.Customize<OrganizationUser>(composer => composer
|
||||
.With(o => o.Type, Type)
|
||||
.With(o => o.Status, Status));
|
||||
}
|
||||
}
|
||||
|
||||
public class OrganizationUserAttribute : CustomizeAttribute
|
||||
{
|
||||
private readonly OrganizationUserStatusType _status;
|
||||
private readonly OrganizationUserType _type;
|
||||
|
||||
public OrganizationUserAttribute(
|
||||
OrganizationUserStatusType status = OrganizationUserStatusType.Confirmed,
|
||||
OrganizationUserType type = OrganizationUserType.User)
|
||||
{
|
||||
_status = status;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public override ICustomization GetCustomization(ParameterInfo parameter)
|
||||
{
|
||||
return new OrganizationUserCustomization(_status, _type);
|
||||
}
|
||||
}
|
||||
|
@ -4,38 +4,37 @@ using AutoFixture.Xunit2;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Test.AutoFixture.PolicyFixtures
|
||||
namespace Bit.Core.Test.AutoFixture.PolicyFixtures;
|
||||
|
||||
internal class PolicyCustomization : ICustomization
|
||||
{
|
||||
internal class PolicyCustomization : ICustomization
|
||||
public PolicyType Type { get; set; }
|
||||
|
||||
public PolicyCustomization(PolicyType type)
|
||||
{
|
||||
public PolicyType Type { get; set; }
|
||||
|
||||
public PolicyCustomization(PolicyType type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<Policy>(composer => composer
|
||||
.With(o => o.OrganizationId, Guid.NewGuid())
|
||||
.With(o => o.Type, Type)
|
||||
.With(o => o.Enabled, true));
|
||||
}
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public class PolicyAttribute : CustomizeAttribute
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
private readonly PolicyType _type;
|
||||
|
||||
public PolicyAttribute(PolicyType type)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public override ICustomization GetCustomization(ParameterInfo parameter)
|
||||
{
|
||||
return new PolicyCustomization(_type);
|
||||
}
|
||||
fixture.Customize<Policy>(composer => composer
|
||||
.With(o => o.OrganizationId, Guid.NewGuid())
|
||||
.With(o => o.Type, Type)
|
||||
.With(o => o.Enabled, true));
|
||||
}
|
||||
}
|
||||
|
||||
public class PolicyAttribute : CustomizeAttribute
|
||||
{
|
||||
private readonly PolicyType _type;
|
||||
|
||||
public PolicyAttribute(PolicyType type)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public override ICustomization GetCustomization(ParameterInfo parameter)
|
||||
{
|
||||
return new PolicyCustomization(_type);
|
||||
}
|
||||
}
|
||||
|
@ -2,63 +2,62 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
namespace Bit.Core.Test.AutoFixture.SendFixtures
|
||||
namespace Bit.Core.Test.AutoFixture.SendFixtures;
|
||||
|
||||
internal class OrganizationSend : ICustomization
|
||||
{
|
||||
internal class OrganizationSend : ICustomization
|
||||
public Guid? OrganizationId { get; set; }
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
public Guid? OrganizationId { get; set; }
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<Send>(composer => composer
|
||||
.With(s => s.OrganizationId, OrganizationId ?? Guid.NewGuid())
|
||||
.Without(s => s.UserId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class UserSend : ICustomization
|
||||
{
|
||||
public Guid? UserId { get; set; }
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<Send>(composer => composer
|
||||
.With(s => s.UserId, UserId ?? Guid.NewGuid())
|
||||
.Without(s => s.OrganizationId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class UserSendAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public UserSendAutoDataAttribute(string userId = null) : base(new SutProviderCustomization(),
|
||||
new UserSend { UserId = userId == null ? (Guid?)null : new Guid(userId) })
|
||||
{ }
|
||||
}
|
||||
internal class InlineUserSendAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineUserSendAutoDataAttribute(params object[] values) : base(new[] { typeof(CurrentContextFixtures.CurrentContext),
|
||||
typeof(SutProviderCustomization), typeof(UserSend) }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineKnownUserSendAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineKnownUserSendAutoDataAttribute(string userId, params object[] values) : base(new ICustomization[]
|
||||
{ new CurrentContextFixtures.CurrentContext(), new SutProviderCustomization(),
|
||||
new UserSend { UserId = new Guid(userId) } }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class OrganizationSendAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public OrganizationSendAutoDataAttribute(string organizationId = null) : base(new CurrentContextFixtures.CurrentContext(),
|
||||
new SutProviderCustomization(),
|
||||
new OrganizationSend { OrganizationId = organizationId == null ? (Guid?)null : new Guid(organizationId) })
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineOrganizationSendAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineOrganizationSendAutoDataAttribute(params object[] values) : base(new[] { typeof(CurrentContextFixtures.CurrentContext),
|
||||
typeof(SutProviderCustomization), typeof(OrganizationSend) }, values)
|
||||
{ }
|
||||
fixture.Customize<Send>(composer => composer
|
||||
.With(s => s.OrganizationId, OrganizationId ?? Guid.NewGuid())
|
||||
.Without(s => s.UserId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class UserSend : ICustomization
|
||||
{
|
||||
public Guid? UserId { get; set; }
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<Send>(composer => composer
|
||||
.With(s => s.UserId, UserId ?? Guid.NewGuid())
|
||||
.Without(s => s.OrganizationId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class UserSendAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public UserSendAutoDataAttribute(string userId = null) : base(new SutProviderCustomization(),
|
||||
new UserSend { UserId = userId == null ? (Guid?)null : new Guid(userId) })
|
||||
{ }
|
||||
}
|
||||
internal class InlineUserSendAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineUserSendAutoDataAttribute(params object[] values) : base(new[] { typeof(CurrentContextFixtures.CurrentContext),
|
||||
typeof(SutProviderCustomization), typeof(UserSend) }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineKnownUserSendAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineKnownUserSendAutoDataAttribute(string userId, params object[] values) : base(new ICustomization[]
|
||||
{ new CurrentContextFixtures.CurrentContext(), new SutProviderCustomization(),
|
||||
new UserSend { UserId = new Guid(userId) } }, values)
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class OrganizationSendAutoDataAttribute : CustomAutoDataAttribute
|
||||
{
|
||||
public OrganizationSendAutoDataAttribute(string organizationId = null) : base(new CurrentContextFixtures.CurrentContext(),
|
||||
new SutProviderCustomization(),
|
||||
new OrganizationSend { OrganizationId = organizationId == null ? (Guid?)null : new Guid(organizationId) })
|
||||
{ }
|
||||
}
|
||||
|
||||
internal class InlineOrganizationSendAutoDataAttribute : InlineCustomAutoDataAttribute
|
||||
{
|
||||
public InlineOrganizationSendAutoDataAttribute(params object[] values) : base(new[] { typeof(CurrentContextFixtures.CurrentContext),
|
||||
typeof(SutProviderCustomization), typeof(OrganizationSend) }, values)
|
||||
{ }
|
||||
}
|
||||
|
@ -6,49 +6,48 @@ using Bit.Core.Models;
|
||||
using Bit.Core.Test.AutoFixture.OrganizationFixtures;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
|
||||
namespace Bit.Core.Test.AutoFixture.UserFixtures
|
||||
namespace Bit.Core.Test.AutoFixture.UserFixtures;
|
||||
|
||||
public class UserBuilder : ISpecimenBuilder
|
||||
{
|
||||
public class UserBuilder : ISpecimenBuilder
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
{
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
if (context == null)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var type = request as Type;
|
||||
if (type == typeof(User))
|
||||
var type = request as Type;
|
||||
if (type == typeof(User))
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
var providers = fixture.Create<Dictionary<TwoFactorProviderType, TwoFactorProvider>>();
|
||||
var user = fixture.WithAutoNSubstitutions().Create<User>();
|
||||
user.SetTwoFactorProviders(providers);
|
||||
return user;
|
||||
}
|
||||
else if (type == typeof(List<User>))
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
var users = fixture.WithAutoNSubstitutions().CreateMany<User>(2);
|
||||
foreach (var user in users)
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
var providers = fixture.Create<Dictionary<TwoFactorProviderType, TwoFactorProvider>>();
|
||||
var user = fixture.WithAutoNSubstitutions().Create<User>();
|
||||
user.SetTwoFactorProviders(providers);
|
||||
return user;
|
||||
}
|
||||
else if (type == typeof(List<User>))
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
var users = fixture.WithAutoNSubstitutions().CreateMany<User>(2);
|
||||
foreach (var user in users)
|
||||
{
|
||||
var providers = fixture.Create<Dictionary<TwoFactorProviderType, TwoFactorProvider>>();
|
||||
user.SetTwoFactorProviders(providers);
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
return new NoSpecimen();
|
||||
return users;
|
||||
}
|
||||
}
|
||||
|
||||
public class UserFixture : ICustomization
|
||||
{
|
||||
public virtual void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customizations.Add(new GlobalSettingsBuilder());
|
||||
fixture.Customizations.Add(new UserBuilder());
|
||||
fixture.Customizations.Add(new OrganizationBuilder());
|
||||
}
|
||||
return new NoSpecimen();
|
||||
}
|
||||
}
|
||||
|
||||
public class UserFixture : ICustomization
|
||||
{
|
||||
public virtual void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customizations.Add(new GlobalSettingsBuilder());
|
||||
fixture.Customizations.Add(new UserBuilder());
|
||||
fixture.Customizations.Add(new OrganizationBuilder());
|
||||
}
|
||||
}
|
||||
|
@ -5,96 +5,95 @@ using Bit.Core.Models;
|
||||
using Bit.Test.Common.Helpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Entities
|
||||
namespace Bit.Core.Test.Entities;
|
||||
|
||||
public class OrganizationTests
|
||||
{
|
||||
public class OrganizationTests
|
||||
private static readonly Dictionary<TwoFactorProviderType, TwoFactorProvider> _testConfig = new Dictionary<TwoFactorProviderType, TwoFactorProvider>()
|
||||
{
|
||||
private static readonly Dictionary<TwoFactorProviderType, TwoFactorProvider> _testConfig = new Dictionary<TwoFactorProviderType, TwoFactorProvider>()
|
||||
[TwoFactorProviderType.OrganizationDuo] = new TwoFactorProvider
|
||||
{
|
||||
[TwoFactorProviderType.OrganizationDuo] = new TwoFactorProvider
|
||||
Enabled = true,
|
||||
MetaData = new Dictionary<string, object>
|
||||
{
|
||||
Enabled = true,
|
||||
MetaData = new Dictionary<string, object>
|
||||
{
|
||||
["IKey"] = "IKey_value",
|
||||
["SKey"] = "SKey_value",
|
||||
["Host"] = "Host_value",
|
||||
},
|
||||
}
|
||||
["IKey"] = "IKey_value",
|
||||
["SKey"] = "SKey_value",
|
||||
["Host"] = "Host_value",
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
[Fact]
|
||||
public void SetTwoFactorProviders_Success()
|
||||
{
|
||||
var organization = new Organization();
|
||||
organization.SetTwoFactorProviders(_testConfig);
|
||||
|
||||
using var jsonDocument = JsonDocument.Parse(organization.TwoFactorProviders);
|
||||
var root = jsonDocument.RootElement;
|
||||
|
||||
var duo = AssertHelper.AssertJsonProperty(root, "6", JsonValueKind.Object);
|
||||
AssertHelper.AssertJsonProperty(duo, "Enabled", JsonValueKind.True);
|
||||
var duoMetaData = AssertHelper.AssertJsonProperty(duo, "MetaData", JsonValueKind.Object);
|
||||
var iKey = AssertHelper.AssertJsonProperty(duoMetaData, "IKey", JsonValueKind.String).GetString();
|
||||
Assert.Equal("IKey_value", iKey);
|
||||
var sKey = AssertHelper.AssertJsonProperty(duoMetaData, "SKey", JsonValueKind.String).GetString();
|
||||
Assert.Equal("SKey_value", sKey);
|
||||
var host = AssertHelper.AssertJsonProperty(duoMetaData, "Host", JsonValueKind.String).GetString();
|
||||
Assert.Equal("Host_value", host);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTwoFactorProviders_Success()
|
||||
{
|
||||
// This is to get rid of the cached dictionary the SetTwoFactorProviders keeps so we can fully test the JSON reading
|
||||
// It intent is to mimic a storing of the entity in the database and it being read later
|
||||
var tempOrganization = new Organization();
|
||||
tempOrganization.SetTwoFactorProviders(_testConfig);
|
||||
var organization = new Organization
|
||||
{
|
||||
TwoFactorProviders = tempOrganization.TwoFactorProviders,
|
||||
};
|
||||
|
||||
var twoFactorProviders = organization.GetTwoFactorProviders();
|
||||
|
||||
[Fact]
|
||||
public void SetTwoFactorProviders_Success()
|
||||
{
|
||||
var organization = new Organization();
|
||||
organization.SetTwoFactorProviders(_testConfig);
|
||||
var duo = Assert.Contains(TwoFactorProviderType.OrganizationDuo, (IDictionary<TwoFactorProviderType, TwoFactorProvider>)twoFactorProviders);
|
||||
Assert.True(duo.Enabled);
|
||||
Assert.NotNull(duo.MetaData);
|
||||
var iKey = Assert.Contains("IKey", (IDictionary<string, object>)duo.MetaData);
|
||||
Assert.Equal("IKey_value", iKey);
|
||||
var sKey = Assert.Contains("SKey", (IDictionary<string, object>)duo.MetaData);
|
||||
Assert.Equal("SKey_value", sKey);
|
||||
var host = Assert.Contains("Host", (IDictionary<string, object>)duo.MetaData);
|
||||
Assert.Equal("Host_value", host);
|
||||
}
|
||||
|
||||
using var jsonDocument = JsonDocument.Parse(organization.TwoFactorProviders);
|
||||
var root = jsonDocument.RootElement;
|
||||
[Fact]
|
||||
public void GetTwoFactorProviders_SavedWithName_Success()
|
||||
{
|
||||
var organization = new Organization();
|
||||
// This should save items with the string name of the enum and we will validate that we can read
|
||||
// from that just incase some organizations have it saved that way.
|
||||
organization.TwoFactorProviders = JsonSerializer.Serialize(_testConfig);
|
||||
|
||||
var duo = AssertHelper.AssertJsonProperty(root, "6", JsonValueKind.Object);
|
||||
AssertHelper.AssertJsonProperty(duo, "Enabled", JsonValueKind.True);
|
||||
var duoMetaData = AssertHelper.AssertJsonProperty(duo, "MetaData", JsonValueKind.Object);
|
||||
var iKey = AssertHelper.AssertJsonProperty(duoMetaData, "IKey", JsonValueKind.String).GetString();
|
||||
Assert.Equal("IKey_value", iKey);
|
||||
var sKey = AssertHelper.AssertJsonProperty(duoMetaData, "SKey", JsonValueKind.String).GetString();
|
||||
Assert.Equal("SKey_value", sKey);
|
||||
var host = AssertHelper.AssertJsonProperty(duoMetaData, "Host", JsonValueKind.String).GetString();
|
||||
Assert.Equal("Host_value", host);
|
||||
}
|
||||
// Preliminary Asserts to make sure we are testing what we want to be testing
|
||||
using var jsonDocument = JsonDocument.Parse(organization.TwoFactorProviders);
|
||||
var root = jsonDocument.RootElement;
|
||||
// This means it saved the enum as its string name
|
||||
AssertHelper.AssertJsonProperty(root, "OrganizationDuo", JsonValueKind.Object);
|
||||
|
||||
[Fact]
|
||||
public void GetTwoFactorProviders_Success()
|
||||
{
|
||||
// This is to get rid of the cached dictionary the SetTwoFactorProviders keeps so we can fully test the JSON reading
|
||||
// It intent is to mimic a storing of the entity in the database and it being read later
|
||||
var tempOrganization = new Organization();
|
||||
tempOrganization.SetTwoFactorProviders(_testConfig);
|
||||
var organization = new Organization
|
||||
{
|
||||
TwoFactorProviders = tempOrganization.TwoFactorProviders,
|
||||
};
|
||||
// Actual checks
|
||||
var twoFactorProviders = organization.GetTwoFactorProviders();
|
||||
|
||||
var twoFactorProviders = organization.GetTwoFactorProviders();
|
||||
|
||||
var duo = Assert.Contains(TwoFactorProviderType.OrganizationDuo, (IDictionary<TwoFactorProviderType, TwoFactorProvider>)twoFactorProviders);
|
||||
Assert.True(duo.Enabled);
|
||||
Assert.NotNull(duo.MetaData);
|
||||
var iKey = Assert.Contains("IKey", (IDictionary<string, object>)duo.MetaData);
|
||||
Assert.Equal("IKey_value", iKey);
|
||||
var sKey = Assert.Contains("SKey", (IDictionary<string, object>)duo.MetaData);
|
||||
Assert.Equal("SKey_value", sKey);
|
||||
var host = Assert.Contains("Host", (IDictionary<string, object>)duo.MetaData);
|
||||
Assert.Equal("Host_value", host);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTwoFactorProviders_SavedWithName_Success()
|
||||
{
|
||||
var organization = new Organization();
|
||||
// This should save items with the string name of the enum and we will validate that we can read
|
||||
// from that just incase some organizations have it saved that way.
|
||||
organization.TwoFactorProviders = JsonSerializer.Serialize(_testConfig);
|
||||
|
||||
// Preliminary Asserts to make sure we are testing what we want to be testing
|
||||
using var jsonDocument = JsonDocument.Parse(organization.TwoFactorProviders);
|
||||
var root = jsonDocument.RootElement;
|
||||
// This means it saved the enum as its string name
|
||||
AssertHelper.AssertJsonProperty(root, "OrganizationDuo", JsonValueKind.Object);
|
||||
|
||||
// Actual checks
|
||||
var twoFactorProviders = organization.GetTwoFactorProviders();
|
||||
|
||||
var duo = Assert.Contains(TwoFactorProviderType.OrganizationDuo, (IDictionary<TwoFactorProviderType, TwoFactorProvider>)twoFactorProviders);
|
||||
Assert.True(duo.Enabled);
|
||||
Assert.NotNull(duo.MetaData);
|
||||
var iKey = Assert.Contains("IKey", (IDictionary<string, object>)duo.MetaData);
|
||||
Assert.Equal("IKey_value", iKey);
|
||||
var sKey = Assert.Contains("SKey", (IDictionary<string, object>)duo.MetaData);
|
||||
Assert.Equal("SKey_value", sKey);
|
||||
var host = Assert.Contains("Host", (IDictionary<string, object>)duo.MetaData);
|
||||
Assert.Equal("Host_value", host);
|
||||
}
|
||||
var duo = Assert.Contains(TwoFactorProviderType.OrganizationDuo, (IDictionary<TwoFactorProviderType, TwoFactorProvider>)twoFactorProviders);
|
||||
Assert.True(duo.Enabled);
|
||||
Assert.NotNull(duo.MetaData);
|
||||
var iKey = Assert.Contains("IKey", (IDictionary<string, object>)duo.MetaData);
|
||||
Assert.Equal("IKey_value", iKey);
|
||||
var sKey = Assert.Contains("SKey", (IDictionary<string, object>)duo.MetaData);
|
||||
Assert.Equal("SKey_value", sKey);
|
||||
var host = Assert.Contains("Host", (IDictionary<string, object>)duo.MetaData);
|
||||
Assert.Equal("Host_value", host);
|
||||
}
|
||||
}
|
||||
|
@ -5,141 +5,140 @@ using Bit.Core.Models;
|
||||
using Bit.Test.Common.Helpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Entities
|
||||
namespace Bit.Core.Test.Entities;
|
||||
|
||||
public class UserTests
|
||||
{
|
||||
public class UserTests
|
||||
// KB MB GB
|
||||
public const long Multiplier = 1024 * 1024 * 1024;
|
||||
|
||||
[Fact]
|
||||
public void StorageBytesRemaining_HasMax_DoesNotHaveStorage_ReturnsMaxAsBytes()
|
||||
{
|
||||
// KB MB GB
|
||||
public const long Multiplier = 1024 * 1024 * 1024;
|
||||
short maxStorageGb = 1;
|
||||
|
||||
[Fact]
|
||||
public void StorageBytesRemaining_HasMax_DoesNotHaveStorage_ReturnsMaxAsBytes()
|
||||
var user = new User
|
||||
{
|
||||
short maxStorageGb = 1;
|
||||
|
||||
var user = new User
|
||||
{
|
||||
MaxStorageGb = maxStorageGb,
|
||||
Storage = null,
|
||||
};
|
||||
|
||||
var bytesRemaining = user.StorageBytesRemaining();
|
||||
|
||||
Assert.Equal(bytesRemaining, maxStorageGb * Multiplier);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(2, 1 * Multiplier, 1 * Multiplier)]
|
||||
|
||||
public void StorageBytesRemaining_HasMax_HasStorage_ReturnRemainingStorage(short maxStorageGb, long storageBytes, long expectedRemainingBytes)
|
||||
{
|
||||
var user = new User
|
||||
{
|
||||
MaxStorageGb = maxStorageGb,
|
||||
Storage = storageBytes,
|
||||
};
|
||||
|
||||
var bytesRemaining = user.StorageBytesRemaining();
|
||||
|
||||
Assert.Equal(expectedRemainingBytes, bytesRemaining);
|
||||
}
|
||||
|
||||
private static readonly Dictionary<TwoFactorProviderType, TwoFactorProvider> _testTwoFactorConfig = new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
{
|
||||
[TwoFactorProviderType.WebAuthn] = new TwoFactorProvider
|
||||
{
|
||||
Enabled = true,
|
||||
MetaData = new Dictionary<string, object>
|
||||
{
|
||||
["Item"] = "thing",
|
||||
},
|
||||
},
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
{
|
||||
Enabled = false,
|
||||
MetaData = new Dictionary<string, object>
|
||||
{
|
||||
["Email"] = "test@email.com",
|
||||
},
|
||||
},
|
||||
MaxStorageGb = maxStorageGb,
|
||||
Storage = null,
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public void SetTwoFactorProviders_Success()
|
||||
var bytesRemaining = user.StorageBytesRemaining();
|
||||
|
||||
Assert.Equal(bytesRemaining, maxStorageGb * Multiplier);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(2, 1 * Multiplier, 1 * Multiplier)]
|
||||
|
||||
public void StorageBytesRemaining_HasMax_HasStorage_ReturnRemainingStorage(short maxStorageGb, long storageBytes, long expectedRemainingBytes)
|
||||
{
|
||||
var user = new User
|
||||
{
|
||||
var user = new User();
|
||||
user.SetTwoFactorProviders(_testTwoFactorConfig);
|
||||
MaxStorageGb = maxStorageGb,
|
||||
Storage = storageBytes,
|
||||
};
|
||||
|
||||
using var jsonDocument = JsonDocument.Parse(user.TwoFactorProviders);
|
||||
var root = jsonDocument.RootElement;
|
||||
var bytesRemaining = user.StorageBytesRemaining();
|
||||
|
||||
var webAuthn = AssertHelper.AssertJsonProperty(root, "7", JsonValueKind.Object);
|
||||
AssertHelper.AssertJsonProperty(webAuthn, "Enabled", JsonValueKind.True);
|
||||
var webMetaData = AssertHelper.AssertJsonProperty(webAuthn, "MetaData", JsonValueKind.Object);
|
||||
AssertHelper.AssertJsonProperty(webMetaData, "Item", JsonValueKind.String);
|
||||
Assert.Equal(expectedRemainingBytes, bytesRemaining);
|
||||
}
|
||||
|
||||
var email = AssertHelper.AssertJsonProperty(root, "1", JsonValueKind.Object);
|
||||
AssertHelper.AssertJsonProperty(email, "Enabled", JsonValueKind.False);
|
||||
var emailMetaData = AssertHelper.AssertJsonProperty(email, "MetaData", JsonValueKind.Object);
|
||||
AssertHelper.AssertJsonProperty(emailMetaData, "Email", JsonValueKind.String);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTwoFactorProviders_Success()
|
||||
private static readonly Dictionary<TwoFactorProviderType, TwoFactorProvider> _testTwoFactorConfig = new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
{
|
||||
[TwoFactorProviderType.WebAuthn] = new TwoFactorProvider
|
||||
{
|
||||
// This is to get rid of the cached dictionary the SetTwoFactorProviders keeps so we can fully test the JSON reading
|
||||
// It intent is to mimic a storing of the entity in the database and it being read later
|
||||
var tempUser = new User();
|
||||
tempUser.SetTwoFactorProviders(_testTwoFactorConfig);
|
||||
var user = new User
|
||||
Enabled = true,
|
||||
MetaData = new Dictionary<string, object>
|
||||
{
|
||||
TwoFactorProviders = tempUser.TwoFactorProviders,
|
||||
};
|
||||
|
||||
var twoFactorProviders = user.GetTwoFactorProviders();
|
||||
|
||||
var webAuthn = Assert.Contains(TwoFactorProviderType.WebAuthn, (IDictionary<TwoFactorProviderType, TwoFactorProvider>)twoFactorProviders);
|
||||
Assert.True(webAuthn.Enabled);
|
||||
Assert.NotNull(webAuthn.MetaData);
|
||||
var webAuthnMetaDataItem = Assert.Contains("Item", (IDictionary<string, object>)webAuthn.MetaData);
|
||||
Assert.Equal("thing", webAuthnMetaDataItem);
|
||||
|
||||
var email = Assert.Contains(TwoFactorProviderType.Email, (IDictionary<TwoFactorProviderType, TwoFactorProvider>)twoFactorProviders);
|
||||
Assert.False(email.Enabled);
|
||||
Assert.NotNull(email.MetaData);
|
||||
var emailMetaDataEmail = Assert.Contains("Email", (IDictionary<string, object>)email.MetaData);
|
||||
Assert.Equal("test@email.com", emailMetaDataEmail);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTwoFactorProviders_SavedWithName_Success()
|
||||
["Item"] = "thing",
|
||||
},
|
||||
},
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
{
|
||||
var user = new User();
|
||||
// This should save items with the string name of the enum and we will validate that we can read
|
||||
// from that just incase some users have it saved that way.
|
||||
user.TwoFactorProviders = JsonSerializer.Serialize(_testTwoFactorConfig);
|
||||
Enabled = false,
|
||||
MetaData = new Dictionary<string, object>
|
||||
{
|
||||
["Email"] = "test@email.com",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Preliminary Asserts to make sure we are testing what we want to be testing
|
||||
using var jsonDocument = JsonDocument.Parse(user.TwoFactorProviders);
|
||||
var root = jsonDocument.RootElement;
|
||||
// This means it saved the enum as its string name
|
||||
AssertHelper.AssertJsonProperty(root, "WebAuthn", JsonValueKind.Object);
|
||||
AssertHelper.AssertJsonProperty(root, "Email", JsonValueKind.Object);
|
||||
[Fact]
|
||||
public void SetTwoFactorProviders_Success()
|
||||
{
|
||||
var user = new User();
|
||||
user.SetTwoFactorProviders(_testTwoFactorConfig);
|
||||
|
||||
// Actual checks
|
||||
var twoFactorProviders = user.GetTwoFactorProviders();
|
||||
using var jsonDocument = JsonDocument.Parse(user.TwoFactorProviders);
|
||||
var root = jsonDocument.RootElement;
|
||||
|
||||
var webAuthn = Assert.Contains(TwoFactorProviderType.WebAuthn, (IDictionary<TwoFactorProviderType, TwoFactorProvider>)twoFactorProviders);
|
||||
Assert.True(webAuthn.Enabled);
|
||||
Assert.NotNull(webAuthn.MetaData);
|
||||
var webAuthnMetaDataItem = Assert.Contains("Item", (IDictionary<string, object>)webAuthn.MetaData);
|
||||
Assert.Equal("thing", webAuthnMetaDataItem);
|
||||
var webAuthn = AssertHelper.AssertJsonProperty(root, "7", JsonValueKind.Object);
|
||||
AssertHelper.AssertJsonProperty(webAuthn, "Enabled", JsonValueKind.True);
|
||||
var webMetaData = AssertHelper.AssertJsonProperty(webAuthn, "MetaData", JsonValueKind.Object);
|
||||
AssertHelper.AssertJsonProperty(webMetaData, "Item", JsonValueKind.String);
|
||||
|
||||
var email = Assert.Contains(TwoFactorProviderType.Email, (IDictionary<TwoFactorProviderType, TwoFactorProvider>)twoFactorProviders);
|
||||
Assert.False(email.Enabled);
|
||||
Assert.NotNull(email.MetaData);
|
||||
var emailMetaDataEmail = Assert.Contains("Email", (IDictionary<string, object>)email.MetaData);
|
||||
Assert.Equal("test@email.com", emailMetaDataEmail);
|
||||
}
|
||||
var email = AssertHelper.AssertJsonProperty(root, "1", JsonValueKind.Object);
|
||||
AssertHelper.AssertJsonProperty(email, "Enabled", JsonValueKind.False);
|
||||
var emailMetaData = AssertHelper.AssertJsonProperty(email, "MetaData", JsonValueKind.Object);
|
||||
AssertHelper.AssertJsonProperty(emailMetaData, "Email", JsonValueKind.String);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTwoFactorProviders_Success()
|
||||
{
|
||||
// This is to get rid of the cached dictionary the SetTwoFactorProviders keeps so we can fully test the JSON reading
|
||||
// It intent is to mimic a storing of the entity in the database and it being read later
|
||||
var tempUser = new User();
|
||||
tempUser.SetTwoFactorProviders(_testTwoFactorConfig);
|
||||
var user = new User
|
||||
{
|
||||
TwoFactorProviders = tempUser.TwoFactorProviders,
|
||||
};
|
||||
|
||||
var twoFactorProviders = user.GetTwoFactorProviders();
|
||||
|
||||
var webAuthn = Assert.Contains(TwoFactorProviderType.WebAuthn, (IDictionary<TwoFactorProviderType, TwoFactorProvider>)twoFactorProviders);
|
||||
Assert.True(webAuthn.Enabled);
|
||||
Assert.NotNull(webAuthn.MetaData);
|
||||
var webAuthnMetaDataItem = Assert.Contains("Item", (IDictionary<string, object>)webAuthn.MetaData);
|
||||
Assert.Equal("thing", webAuthnMetaDataItem);
|
||||
|
||||
var email = Assert.Contains(TwoFactorProviderType.Email, (IDictionary<TwoFactorProviderType, TwoFactorProvider>)twoFactorProviders);
|
||||
Assert.False(email.Enabled);
|
||||
Assert.NotNull(email.MetaData);
|
||||
var emailMetaDataEmail = Assert.Contains("Email", (IDictionary<string, object>)email.MetaData);
|
||||
Assert.Equal("test@email.com", emailMetaDataEmail);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTwoFactorProviders_SavedWithName_Success()
|
||||
{
|
||||
var user = new User();
|
||||
// This should save items with the string name of the enum and we will validate that we can read
|
||||
// from that just incase some users have it saved that way.
|
||||
user.TwoFactorProviders = JsonSerializer.Serialize(_testTwoFactorConfig);
|
||||
|
||||
// Preliminary Asserts to make sure we are testing what we want to be testing
|
||||
using var jsonDocument = JsonDocument.Parse(user.TwoFactorProviders);
|
||||
var root = jsonDocument.RootElement;
|
||||
// This means it saved the enum as its string name
|
||||
AssertHelper.AssertJsonProperty(root, "WebAuthn", JsonValueKind.Object);
|
||||
AssertHelper.AssertJsonProperty(root, "Email", JsonValueKind.Object);
|
||||
|
||||
// Actual checks
|
||||
var twoFactorProviders = user.GetTwoFactorProviders();
|
||||
|
||||
var webAuthn = Assert.Contains(TwoFactorProviderType.WebAuthn, (IDictionary<TwoFactorProviderType, TwoFactorProvider>)twoFactorProviders);
|
||||
Assert.True(webAuthn.Enabled);
|
||||
Assert.NotNull(webAuthn.MetaData);
|
||||
var webAuthnMetaDataItem = Assert.Contains("Item", (IDictionary<string, object>)webAuthn.MetaData);
|
||||
Assert.Equal("thing", webAuthnMetaDataItem);
|
||||
|
||||
var email = Assert.Contains(TwoFactorProviderType.Email, (IDictionary<TwoFactorProviderType, TwoFactorProvider>)twoFactorProviders);
|
||||
Assert.False(email.Enabled);
|
||||
Assert.NotNull(email.MetaData);
|
||||
var emailMetaDataEmail = Assert.Contains("Email", (IDictionary<string, object>)email.MetaData);
|
||||
Assert.Equal("test@email.com", emailMetaDataEmail);
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
using Bit.Core.Settings;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Bit.Core.Test.Helpers.Factories
|
||||
namespace Bit.Core.Test.Helpers.Factories;
|
||||
|
||||
public static class GlobalSettingsFactory
|
||||
{
|
||||
public static class GlobalSettingsFactory
|
||||
public static GlobalSettings GlobalSettings { get; } = new();
|
||||
static GlobalSettingsFactory()
|
||||
{
|
||||
public static GlobalSettings GlobalSettings { get; } = new();
|
||||
static GlobalSettingsFactory()
|
||||
{
|
||||
var configBuilder = new ConfigurationBuilder().AddUserSecrets("bitwarden-Api");
|
||||
var Configuration = configBuilder.Build();
|
||||
ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), GlobalSettings);
|
||||
}
|
||||
var configBuilder = new ConfigurationBuilder().AddUserSecrets("bitwarden-Api");
|
||||
var Configuration = configBuilder.Build();
|
||||
ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), GlobalSettings);
|
||||
}
|
||||
}
|
||||
|
@ -5,35 +5,34 @@ using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Identity
|
||||
namespace Bit.Core.Test.Identity;
|
||||
|
||||
public class AuthenticationTokenProviderTests : BaseTokenProviderTests<AuthenticatorTokenProvider>
|
||||
{
|
||||
public class AuthenticationTokenProviderTests : BaseTokenProviderTests<AuthenticatorTokenProvider>
|
||||
public override TwoFactorProviderType TwoFactorProviderType => TwoFactorProviderType.Authenticator;
|
||||
|
||||
public static IEnumerable<object[]> CanGenerateTwoFactorTokenAsyncData
|
||||
=> SetupCanGenerateData(
|
||||
(
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
["Key"] = "stuff",
|
||||
},
|
||||
true
|
||||
),
|
||||
(
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
["Key"] = ""
|
||||
},
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
[Theory, BitMemberAutoData(nameof(CanGenerateTwoFactorTokenAsyncData))]
|
||||
public override async Task RunCanGenerateTwoFactorTokenAsync(Dictionary<string, object> metaData, bool expectedResponse,
|
||||
User user, SutProvider<AuthenticatorTokenProvider> sutProvider)
|
||||
{
|
||||
public override TwoFactorProviderType TwoFactorProviderType => TwoFactorProviderType.Authenticator;
|
||||
|
||||
public static IEnumerable<object[]> CanGenerateTwoFactorTokenAsyncData
|
||||
=> SetupCanGenerateData(
|
||||
(
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
["Key"] = "stuff",
|
||||
},
|
||||
true
|
||||
),
|
||||
(
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
["Key"] = ""
|
||||
},
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
[Theory, BitMemberAutoData(nameof(CanGenerateTwoFactorTokenAsyncData))]
|
||||
public override async Task RunCanGenerateTwoFactorTokenAsync(Dictionary<string, object> metaData, bool expectedResponse,
|
||||
User user, SutProvider<AuthenticatorTokenProvider> sutProvider)
|
||||
{
|
||||
await base.RunCanGenerateTwoFactorTokenAsync(metaData, expectedResponse, user, sutProvider);
|
||||
}
|
||||
await base.RunCanGenerateTwoFactorTokenAsync(metaData, expectedResponse, user, sutProvider);
|
||||
}
|
||||
}
|
||||
|
@ -11,83 +11,82 @@ using Microsoft.Extensions.Options;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Identity
|
||||
namespace Bit.Core.Test.Identity;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public abstract class BaseTokenProviderTests<T>
|
||||
where T : IUserTwoFactorTokenProvider<User>
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
public abstract class BaseTokenProviderTests<T>
|
||||
where T : IUserTwoFactorTokenProvider<User>
|
||||
public abstract TwoFactorProviderType TwoFactorProviderType { get; }
|
||||
|
||||
#region Helpers
|
||||
protected static IEnumerable<object[]> SetupCanGenerateData(params (Dictionary<string, object> MetaData, bool ExpectedResponse)[] data)
|
||||
{
|
||||
public abstract TwoFactorProviderType TwoFactorProviderType { get; }
|
||||
|
||||
#region Helpers
|
||||
protected static IEnumerable<object[]> SetupCanGenerateData(params (Dictionary<string, object> MetaData, bool ExpectedResponse)[] data)
|
||||
{
|
||||
return data.Select(d =>
|
||||
new object[]
|
||||
{
|
||||
d.MetaData,
|
||||
d.ExpectedResponse,
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual IUserService AdditionalSetup(SutProvider<T> sutProvider, User user)
|
||||
{
|
||||
var userService = Substitute.For<IUserService>();
|
||||
|
||||
sutProvider.GetDependency<IServiceProvider>()
|
||||
.GetService(typeof(IUserService))
|
||||
.Returns(userService);
|
||||
|
||||
SetupUserService(userService, user);
|
||||
|
||||
return userService;
|
||||
}
|
||||
|
||||
protected virtual void SetupUserService(IUserService userService, User user)
|
||||
{
|
||||
userService
|
||||
.TwoFactorProviderIsEnabledAsync(TwoFactorProviderType, user)
|
||||
.Returns(true);
|
||||
}
|
||||
|
||||
protected static UserManager<User> SubstituteUserManager()
|
||||
{
|
||||
return new UserManager<User>(Substitute.For<IUserStore<User>>(),
|
||||
Substitute.For<IOptions<IdentityOptions>>(),
|
||||
Substitute.For<IPasswordHasher<User>>(),
|
||||
Enumerable.Empty<IUserValidator<User>>(),
|
||||
Enumerable.Empty<IPasswordValidator<User>>(),
|
||||
Substitute.For<ILookupNormalizer>(),
|
||||
Substitute.For<IdentityErrorDescriber>(),
|
||||
Substitute.For<IServiceProvider>(),
|
||||
Substitute.For<ILogger<UserManager<User>>>());
|
||||
}
|
||||
|
||||
protected void MockDatabase(User user, Dictionary<string, object> metaData)
|
||||
{
|
||||
var providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
return data.Select(d =>
|
||||
new object[]
|
||||
{
|
||||
[TwoFactorProviderType] = new TwoFactorProvider
|
||||
{
|
||||
Enabled = true,
|
||||
MetaData = metaData,
|
||||
},
|
||||
};
|
||||
d.MetaData,
|
||||
d.ExpectedResponse,
|
||||
});
|
||||
}
|
||||
|
||||
user.TwoFactorProviders = JsonHelpers.LegacySerialize(providers);
|
||||
}
|
||||
#endregion
|
||||
protected virtual IUserService AdditionalSetup(SutProvider<T> sutProvider, User user)
|
||||
{
|
||||
var userService = Substitute.For<IUserService>();
|
||||
|
||||
public virtual async Task RunCanGenerateTwoFactorTokenAsync(Dictionary<string, object> metaData, bool expectedResponse,
|
||||
User user, SutProvider<T> sutProvider)
|
||||
sutProvider.GetDependency<IServiceProvider>()
|
||||
.GetService(typeof(IUserService))
|
||||
.Returns(userService);
|
||||
|
||||
SetupUserService(userService, user);
|
||||
|
||||
return userService;
|
||||
}
|
||||
|
||||
protected virtual void SetupUserService(IUserService userService, User user)
|
||||
{
|
||||
userService
|
||||
.TwoFactorProviderIsEnabledAsync(TwoFactorProviderType, user)
|
||||
.Returns(true);
|
||||
}
|
||||
|
||||
protected static UserManager<User> SubstituteUserManager()
|
||||
{
|
||||
return new UserManager<User>(Substitute.For<IUserStore<User>>(),
|
||||
Substitute.For<IOptions<IdentityOptions>>(),
|
||||
Substitute.For<IPasswordHasher<User>>(),
|
||||
Enumerable.Empty<IUserValidator<User>>(),
|
||||
Enumerable.Empty<IPasswordValidator<User>>(),
|
||||
Substitute.For<ILookupNormalizer>(),
|
||||
Substitute.For<IdentityErrorDescriber>(),
|
||||
Substitute.For<IServiceProvider>(),
|
||||
Substitute.For<ILogger<UserManager<User>>>());
|
||||
}
|
||||
|
||||
protected void MockDatabase(User user, Dictionary<string, object> metaData)
|
||||
{
|
||||
var providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
{
|
||||
var userManager = SubstituteUserManager();
|
||||
MockDatabase(user, metaData);
|
||||
[TwoFactorProviderType] = new TwoFactorProvider
|
||||
{
|
||||
Enabled = true,
|
||||
MetaData = metaData,
|
||||
},
|
||||
};
|
||||
|
||||
AdditionalSetup(sutProvider, user);
|
||||
user.TwoFactorProviders = JsonHelpers.LegacySerialize(providers);
|
||||
}
|
||||
#endregion
|
||||
|
||||
var response = await sutProvider.Sut.CanGenerateTwoFactorTokenAsync(userManager, user);
|
||||
Assert.Equal(expectedResponse, response);
|
||||
}
|
||||
public virtual async Task RunCanGenerateTwoFactorTokenAsync(Dictionary<string, object> metaData, bool expectedResponse,
|
||||
User user, SutProvider<T> sutProvider)
|
||||
{
|
||||
var userManager = SubstituteUserManager();
|
||||
MockDatabase(user, metaData);
|
||||
|
||||
AdditionalSetup(sutProvider, user);
|
||||
|
||||
var response = await sutProvider.Sut.CanGenerateTwoFactorTokenAsync(userManager, user);
|
||||
Assert.Equal(expectedResponse, response);
|
||||
}
|
||||
}
|
||||
|
@ -5,42 +5,41 @@ using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Identity
|
||||
namespace Bit.Core.Test.Identity;
|
||||
|
||||
public class EmailTokenProviderTests : BaseTokenProviderTests<EmailTokenProvider>
|
||||
{
|
||||
public class EmailTokenProviderTests : BaseTokenProviderTests<EmailTokenProvider>
|
||||
public override TwoFactorProviderType TwoFactorProviderType => TwoFactorProviderType.Email;
|
||||
|
||||
public static IEnumerable<object[]> CanGenerateTwoFactorTokenAsyncData
|
||||
=> SetupCanGenerateData(
|
||||
(
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
["Email"] = "test@email.com",
|
||||
},
|
||||
true
|
||||
),
|
||||
(
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
["NotEmail"] = "value",
|
||||
},
|
||||
false
|
||||
),
|
||||
(
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
["Email"] = "",
|
||||
},
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
[Theory, BitMemberAutoData(nameof(CanGenerateTwoFactorTokenAsyncData))]
|
||||
public override async Task RunCanGenerateTwoFactorTokenAsync(Dictionary<string, object> metaData, bool expectedResponse,
|
||||
User user, SutProvider<EmailTokenProvider> sutProvider)
|
||||
{
|
||||
public override TwoFactorProviderType TwoFactorProviderType => TwoFactorProviderType.Email;
|
||||
|
||||
public static IEnumerable<object[]> CanGenerateTwoFactorTokenAsyncData
|
||||
=> SetupCanGenerateData(
|
||||
(
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
["Email"] = "test@email.com",
|
||||
},
|
||||
true
|
||||
),
|
||||
(
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
["NotEmail"] = "value",
|
||||
},
|
||||
false
|
||||
),
|
||||
(
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
["Email"] = "",
|
||||
},
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
[Theory, BitMemberAutoData(nameof(CanGenerateTwoFactorTokenAsyncData))]
|
||||
public override async Task RunCanGenerateTwoFactorTokenAsync(Dictionary<string, object> metaData, bool expectedResponse,
|
||||
User user, SutProvider<EmailTokenProvider> sutProvider)
|
||||
{
|
||||
await base.RunCanGenerateTwoFactorTokenAsync(metaData, expectedResponse, user, sutProvider);
|
||||
}
|
||||
await base.RunCanGenerateTwoFactorTokenAsync(metaData, expectedResponse, user, sutProvider);
|
||||
}
|
||||
}
|
||||
|
@ -4,91 +4,90 @@ using Microsoft.Extensions.Primitives;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.IdentityServer
|
||||
namespace Bit.Core.Test.IdentityServer;
|
||||
|
||||
public class TokenRetrievalTests
|
||||
{
|
||||
public class TokenRetrievalTests
|
||||
private readonly Func<HttpRequest, string> _sut = TokenRetrieval.FromAuthorizationHeaderOrQueryString();
|
||||
|
||||
[Fact]
|
||||
public void RetrieveToken_FromHeader_ReturnsToken()
|
||||
{
|
||||
private readonly Func<HttpRequest, string> _sut = TokenRetrieval.FromAuthorizationHeaderOrQueryString();
|
||||
|
||||
[Fact]
|
||||
public void RetrieveToken_FromHeader_ReturnsToken()
|
||||
// Arrange
|
||||
var headers = new HeaderDictionary
|
||||
{
|
||||
// Arrange
|
||||
var headers = new HeaderDictionary
|
||||
{
|
||||
{ "Authorization", "Bearer test_value" },
|
||||
{ "X-Test-Header", "random_value" }
|
||||
};
|
||||
{ "Authorization", "Bearer test_value" },
|
||||
{ "X-Test-Header", "random_value" }
|
||||
};
|
||||
|
||||
var request = Substitute.For<HttpRequest>();
|
||||
var request = Substitute.For<HttpRequest>();
|
||||
|
||||
request.Headers.Returns(headers);
|
||||
request.Headers.Returns(headers);
|
||||
|
||||
// Act
|
||||
var token = _sut(request);
|
||||
// Act
|
||||
var token = _sut(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("test_value", token);
|
||||
}
|
||||
// Assert
|
||||
Assert.Equal("test_value", token);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RetrieveToken_FromQueryString_ReturnsToken()
|
||||
[Fact]
|
||||
public void RetrieveToken_FromQueryString_ReturnsToken()
|
||||
{
|
||||
// Arrange
|
||||
var queryString = new Dictionary<string, StringValues>
|
||||
{
|
||||
// Arrange
|
||||
var queryString = new Dictionary<string, StringValues>
|
||||
{
|
||||
{ "access_token", "test_value" },
|
||||
{ "test-query", "random_value" }
|
||||
};
|
||||
{ "access_token", "test_value" },
|
||||
{ "test-query", "random_value" }
|
||||
};
|
||||
|
||||
var request = Substitute.For<HttpRequest>();
|
||||
request.Query.Returns(new QueryCollection(queryString));
|
||||
var request = Substitute.For<HttpRequest>();
|
||||
request.Query.Returns(new QueryCollection(queryString));
|
||||
|
||||
// Act
|
||||
var token = _sut(request);
|
||||
// Act
|
||||
var token = _sut(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("test_value", token);
|
||||
}
|
||||
// Assert
|
||||
Assert.Equal("test_value", token);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RetrieveToken_HasBoth_ReturnsHeaderToken()
|
||||
[Fact]
|
||||
public void RetrieveToken_HasBoth_ReturnsHeaderToken()
|
||||
{
|
||||
// Arrange
|
||||
var queryString = new Dictionary<string, StringValues>
|
||||
{
|
||||
// Arrange
|
||||
var queryString = new Dictionary<string, StringValues>
|
||||
{
|
||||
{ "access_token", "query_string_token" },
|
||||
{ "test-query", "random_value" }
|
||||
};
|
||||
{ "access_token", "query_string_token" },
|
||||
{ "test-query", "random_value" }
|
||||
};
|
||||
|
||||
var headers = new HeaderDictionary
|
||||
{
|
||||
{ "Authorization", "Bearer header_token" },
|
||||
{ "X-Test-Header", "random_value" }
|
||||
};
|
||||
|
||||
var request = Substitute.For<HttpRequest>();
|
||||
request.Headers.Returns(headers);
|
||||
request.Query.Returns(new QueryCollection(queryString));
|
||||
|
||||
// Act
|
||||
var token = _sut(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("header_token", token);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RetrieveToken_NoToken_ReturnsNull()
|
||||
var headers = new HeaderDictionary
|
||||
{
|
||||
// Arrange
|
||||
var request = Substitute.For<HttpRequest>();
|
||||
{ "Authorization", "Bearer header_token" },
|
||||
{ "X-Test-Header", "random_value" }
|
||||
};
|
||||
|
||||
// Act
|
||||
var token = _sut(request);
|
||||
var request = Substitute.For<HttpRequest>();
|
||||
request.Headers.Returns(headers);
|
||||
request.Query.Returns(new QueryCollection(queryString));
|
||||
|
||||
// Assert
|
||||
Assert.Null(token);
|
||||
}
|
||||
// Act
|
||||
var token = _sut(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("header_token", token);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RetrieveToken_NoToken_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
var request = Substitute.For<HttpRequest>();
|
||||
|
||||
// Act
|
||||
var token = _sut(request);
|
||||
|
||||
// Assert
|
||||
Assert.Null(token);
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,22 @@
|
||||
using Bit.Core.Models.Business;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Models.Business
|
||||
namespace Bit.Core.Test.Models.Business;
|
||||
|
||||
public class BillingInfoTests
|
||||
{
|
||||
public class BillingInfoTests
|
||||
[Fact]
|
||||
public void BillingInvoice_Amount_ShouldComeFrom_InvoiceTotal()
|
||||
{
|
||||
[Fact]
|
||||
public void BillingInvoice_Amount_ShouldComeFrom_InvoiceTotal()
|
||||
var invoice = new Stripe.Invoice
|
||||
{
|
||||
var invoice = new Stripe.Invoice
|
||||
{
|
||||
AmountDue = 1000,
|
||||
Total = 2000,
|
||||
};
|
||||
AmountDue = 1000,
|
||||
Total = 2000,
|
||||
};
|
||||
|
||||
var billingInvoice = new BillingInfo.BillingInvoice(invoice);
|
||||
var billingInvoice = new BillingInfo.BillingInvoice(invoice);
|
||||
|
||||
// Should have been set from Total
|
||||
Assert.Equal(20M, billingInvoice.Amount);
|
||||
}
|
||||
// Should have been set from Total
|
||||
Assert.Equal(20M, billingInvoice.Amount);
|
||||
}
|
||||
}
|
||||
|
@ -1,115 +1,114 @@
|
||||
using Bit.Core.Models.Business;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Models.Business
|
||||
namespace Bit.Core.Test.Models.Business;
|
||||
|
||||
public class TaxInfoTests
|
||||
{
|
||||
public class TaxInfoTests
|
||||
// PH = Placeholder
|
||||
[Theory]
|
||||
[InlineData(null, null, null, null)]
|
||||
[InlineData("", "", null, null)]
|
||||
[InlineData("PH", "", null, null)]
|
||||
[InlineData("", "PH", null, null)]
|
||||
[InlineData("AE", "PH", null, "ae_trn")]
|
||||
[InlineData("AU", "PH", null, "au_abn")]
|
||||
[InlineData("BR", "PH", null, "br_cnpj")]
|
||||
[InlineData("CA", "PH", "bec", "ca_qst")]
|
||||
[InlineData("CA", "PH", null, "ca_bn")]
|
||||
[InlineData("CL", "PH", null, "cl_tin")]
|
||||
[InlineData("AT", "PH", null, "eu_vat")]
|
||||
[InlineData("BE", "PH", null, "eu_vat")]
|
||||
[InlineData("BG", "PH", null, "eu_vat")]
|
||||
[InlineData("CY", "PH", null, "eu_vat")]
|
||||
[InlineData("CZ", "PH", null, "eu_vat")]
|
||||
[InlineData("DE", "PH", null, "eu_vat")]
|
||||
[InlineData("DK", "PH", null, "eu_vat")]
|
||||
[InlineData("EE", "PH", null, "eu_vat")]
|
||||
[InlineData("ES", "PH", null, "eu_vat")]
|
||||
[InlineData("FI", "PH", null, "eu_vat")]
|
||||
[InlineData("FR", "PH", null, "eu_vat")]
|
||||
[InlineData("GB", "PH", null, "eu_vat")]
|
||||
[InlineData("GR", "PH", null, "eu_vat")]
|
||||
[InlineData("HR", "PH", null, "eu_vat")]
|
||||
[InlineData("HU", "PH", null, "eu_vat")]
|
||||
[InlineData("IE", "PH", null, "eu_vat")]
|
||||
[InlineData("IT", "PH", null, "eu_vat")]
|
||||
[InlineData("LT", "PH", null, "eu_vat")]
|
||||
[InlineData("LU", "PH", null, "eu_vat")]
|
||||
[InlineData("LV", "PH", null, "eu_vat")]
|
||||
[InlineData("MT", "PH", null, "eu_vat")]
|
||||
[InlineData("NL", "PH", null, "eu_vat")]
|
||||
[InlineData("PL", "PH", null, "eu_vat")]
|
||||
[InlineData("PT", "PH", null, "eu_vat")]
|
||||
[InlineData("RO", "PH", null, "eu_vat")]
|
||||
[InlineData("SE", "PH", null, "eu_vat")]
|
||||
[InlineData("SI", "PH", null, "eu_vat")]
|
||||
[InlineData("SK", "PH", null, "eu_vat")]
|
||||
[InlineData("HK", "PH", null, "hk_br")]
|
||||
[InlineData("IN", "PH", null, "in_gst")]
|
||||
[InlineData("JP", "PH", null, "jp_cn")]
|
||||
[InlineData("KR", "PH", null, "kr_brn")]
|
||||
[InlineData("LI", "PH", null, "li_uid")]
|
||||
[InlineData("MX", "PH", null, "mx_rfc")]
|
||||
[InlineData("MY", "PH", null, "my_sst")]
|
||||
[InlineData("NO", "PH", null, "no_vat")]
|
||||
[InlineData("NZ", "PH", null, "nz_gst")]
|
||||
[InlineData("RU", "PH", null, "ru_inn")]
|
||||
[InlineData("SA", "PH", null, "sa_vat")]
|
||||
[InlineData("SG", "PH", null, "sg_gst")]
|
||||
[InlineData("TH", "PH", null, "th_vat")]
|
||||
[InlineData("TW", "PH", null, "tw_vat")]
|
||||
[InlineData("US", "PH", null, "us_ein")]
|
||||
[InlineData("ZA", "PH", null, "za_vat")]
|
||||
[InlineData("ABCDEF", "PH", null, null)]
|
||||
public void GetTaxIdType_Success(string billingAddressCountry,
|
||||
string taxIdNumber,
|
||||
string billingAddressState,
|
||||
string expectedTaxIdType)
|
||||
{
|
||||
// PH = Placeholder
|
||||
[Theory]
|
||||
[InlineData(null, null, null, null)]
|
||||
[InlineData("", "", null, null)]
|
||||
[InlineData("PH", "", null, null)]
|
||||
[InlineData("", "PH", null, null)]
|
||||
[InlineData("AE", "PH", null, "ae_trn")]
|
||||
[InlineData("AU", "PH", null, "au_abn")]
|
||||
[InlineData("BR", "PH", null, "br_cnpj")]
|
||||
[InlineData("CA", "PH", "bec", "ca_qst")]
|
||||
[InlineData("CA", "PH", null, "ca_bn")]
|
||||
[InlineData("CL", "PH", null, "cl_tin")]
|
||||
[InlineData("AT", "PH", null, "eu_vat")]
|
||||
[InlineData("BE", "PH", null, "eu_vat")]
|
||||
[InlineData("BG", "PH", null, "eu_vat")]
|
||||
[InlineData("CY", "PH", null, "eu_vat")]
|
||||
[InlineData("CZ", "PH", null, "eu_vat")]
|
||||
[InlineData("DE", "PH", null, "eu_vat")]
|
||||
[InlineData("DK", "PH", null, "eu_vat")]
|
||||
[InlineData("EE", "PH", null, "eu_vat")]
|
||||
[InlineData("ES", "PH", null, "eu_vat")]
|
||||
[InlineData("FI", "PH", null, "eu_vat")]
|
||||
[InlineData("FR", "PH", null, "eu_vat")]
|
||||
[InlineData("GB", "PH", null, "eu_vat")]
|
||||
[InlineData("GR", "PH", null, "eu_vat")]
|
||||
[InlineData("HR", "PH", null, "eu_vat")]
|
||||
[InlineData("HU", "PH", null, "eu_vat")]
|
||||
[InlineData("IE", "PH", null, "eu_vat")]
|
||||
[InlineData("IT", "PH", null, "eu_vat")]
|
||||
[InlineData("LT", "PH", null, "eu_vat")]
|
||||
[InlineData("LU", "PH", null, "eu_vat")]
|
||||
[InlineData("LV", "PH", null, "eu_vat")]
|
||||
[InlineData("MT", "PH", null, "eu_vat")]
|
||||
[InlineData("NL", "PH", null, "eu_vat")]
|
||||
[InlineData("PL", "PH", null, "eu_vat")]
|
||||
[InlineData("PT", "PH", null, "eu_vat")]
|
||||
[InlineData("RO", "PH", null, "eu_vat")]
|
||||
[InlineData("SE", "PH", null, "eu_vat")]
|
||||
[InlineData("SI", "PH", null, "eu_vat")]
|
||||
[InlineData("SK", "PH", null, "eu_vat")]
|
||||
[InlineData("HK", "PH", null, "hk_br")]
|
||||
[InlineData("IN", "PH", null, "in_gst")]
|
||||
[InlineData("JP", "PH", null, "jp_cn")]
|
||||
[InlineData("KR", "PH", null, "kr_brn")]
|
||||
[InlineData("LI", "PH", null, "li_uid")]
|
||||
[InlineData("MX", "PH", null, "mx_rfc")]
|
||||
[InlineData("MY", "PH", null, "my_sst")]
|
||||
[InlineData("NO", "PH", null, "no_vat")]
|
||||
[InlineData("NZ", "PH", null, "nz_gst")]
|
||||
[InlineData("RU", "PH", null, "ru_inn")]
|
||||
[InlineData("SA", "PH", null, "sa_vat")]
|
||||
[InlineData("SG", "PH", null, "sg_gst")]
|
||||
[InlineData("TH", "PH", null, "th_vat")]
|
||||
[InlineData("TW", "PH", null, "tw_vat")]
|
||||
[InlineData("US", "PH", null, "us_ein")]
|
||||
[InlineData("ZA", "PH", null, "za_vat")]
|
||||
[InlineData("ABCDEF", "PH", null, null)]
|
||||
public void GetTaxIdType_Success(string billingAddressCountry,
|
||||
string taxIdNumber,
|
||||
string billingAddressState,
|
||||
string expectedTaxIdType)
|
||||
var taxInfo = new TaxInfo
|
||||
{
|
||||
var taxInfo = new TaxInfo
|
||||
{
|
||||
BillingAddressCountry = billingAddressCountry,
|
||||
TaxIdNumber = taxIdNumber,
|
||||
BillingAddressState = billingAddressState,
|
||||
};
|
||||
BillingAddressCountry = billingAddressCountry,
|
||||
TaxIdNumber = taxIdNumber,
|
||||
BillingAddressState = billingAddressState,
|
||||
};
|
||||
|
||||
Assert.Equal(expectedTaxIdType, taxInfo.TaxIdType);
|
||||
}
|
||||
Assert.Equal(expectedTaxIdType, taxInfo.TaxIdType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTaxIdType_CreateOnce_ReturnCacheSecondTime()
|
||||
[Fact]
|
||||
public void GetTaxIdType_CreateOnce_ReturnCacheSecondTime()
|
||||
{
|
||||
var taxInfo = new TaxInfo
|
||||
{
|
||||
var taxInfo = new TaxInfo
|
||||
{
|
||||
BillingAddressCountry = "US",
|
||||
TaxIdNumber = "PH",
|
||||
BillingAddressState = null,
|
||||
};
|
||||
BillingAddressCountry = "US",
|
||||
TaxIdNumber = "PH",
|
||||
BillingAddressState = null,
|
||||
};
|
||||
|
||||
Assert.Equal("us_ein", taxInfo.TaxIdType);
|
||||
Assert.Equal("us_ein", taxInfo.TaxIdType);
|
||||
|
||||
// Per the current spec even if the values change to something other than null it
|
||||
// will return the cached version of TaxIdType.
|
||||
taxInfo.BillingAddressCountry = "ZA";
|
||||
// Per the current spec even if the values change to something other than null it
|
||||
// will return the cached version of TaxIdType.
|
||||
taxInfo.BillingAddressCountry = "ZA";
|
||||
|
||||
Assert.Equal("us_ein", taxInfo.TaxIdType);
|
||||
}
|
||||
Assert.Equal("us_ein", taxInfo.TaxIdType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null, false)]
|
||||
[InlineData("123", "US", true)]
|
||||
[InlineData("123", "ZQ12", false)]
|
||||
[InlineData(" ", "US", false)]
|
||||
public void HasTaxId_ReturnsExpected(string taxIdNumber, string billingAddressCountry, bool expected)
|
||||
[Theory]
|
||||
[InlineData(null, null, false)]
|
||||
[InlineData("123", "US", true)]
|
||||
[InlineData("123", "ZQ12", false)]
|
||||
[InlineData(" ", "US", false)]
|
||||
public void HasTaxId_ReturnsExpected(string taxIdNumber, string billingAddressCountry, bool expected)
|
||||
{
|
||||
var taxInfo = new TaxInfo
|
||||
{
|
||||
var taxInfo = new TaxInfo
|
||||
{
|
||||
TaxIdNumber = taxIdNumber,
|
||||
BillingAddressCountry = billingAddressCountry,
|
||||
};
|
||||
TaxIdNumber = taxIdNumber,
|
||||
BillingAddressCountry = billingAddressCountry,
|
||||
};
|
||||
|
||||
Assert.Equal(expected, taxInfo.HasTaxId);
|
||||
}
|
||||
Assert.Equal(expected, taxInfo.HasTaxId);
|
||||
}
|
||||
}
|
||||
|
@ -4,30 +4,29 @@ using Bit.Core.Models.Business.Tokenables;
|
||||
using Bit.Core.Tokens;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Models.Business.Tokenables
|
||||
namespace Bit.Core.Test.Models.Business.Tokenables;
|
||||
|
||||
public class EmergencyAccessInviteTokenableTests
|
||||
{
|
||||
public class EmergencyAccessInviteTokenableTests
|
||||
[Theory, AutoData]
|
||||
public void SerializationSetsCorrectDateTime(EmergencyAccess emergencyAccess)
|
||||
{
|
||||
[Theory, AutoData]
|
||||
public void SerializationSetsCorrectDateTime(EmergencyAccess emergencyAccess)
|
||||
{
|
||||
var token = new EmergencyAccessInviteTokenable(emergencyAccess, 2);
|
||||
Assert.Equal(Tokenable.FromToken<EmergencyAccessInviteTokenable>(token.ToToken().ToString()).ExpirationDate,
|
||||
token.ExpirationDate,
|
||||
TimeSpan.FromMilliseconds(10));
|
||||
}
|
||||
var token = new EmergencyAccessInviteTokenable(emergencyAccess, 2);
|
||||
Assert.Equal(Tokenable.FromToken<EmergencyAccessInviteTokenable>(token.ToToken().ToString()).ExpirationDate,
|
||||
token.ExpirationDate,
|
||||
TimeSpan.FromMilliseconds(10));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsInvalidIfIdentifierIsWrong()
|
||||
[Fact]
|
||||
public void IsInvalidIfIdentifierIsWrong()
|
||||
{
|
||||
var token = new EmergencyAccessInviteTokenable(DateTime.MaxValue)
|
||||
{
|
||||
var token = new EmergencyAccessInviteTokenable(DateTime.MaxValue)
|
||||
{
|
||||
Email = "email",
|
||||
Id = Guid.NewGuid(),
|
||||
Identifier = "not correct"
|
||||
};
|
||||
Email = "email",
|
||||
Id = Guid.NewGuid(),
|
||||
Identifier = "not correct"
|
||||
};
|
||||
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
}
|
||||
|
@ -5,84 +5,83 @@ using Bit.Core.Tokens;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Models.Business.Tokenables
|
||||
namespace Bit.Core.Test.Models.Business.Tokenables;
|
||||
|
||||
public class HCaptchaTokenableTests
|
||||
{
|
||||
public class HCaptchaTokenableTests
|
||||
[Fact]
|
||||
public void CanHandleNullUser()
|
||||
{
|
||||
[Fact]
|
||||
public void CanHandleNullUser()
|
||||
var token = new HCaptchaTokenable(null);
|
||||
|
||||
Assert.Equal(default, token.Id);
|
||||
Assert.Equal(default, token.Email);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TokenWithNullUserIsInvalid()
|
||||
{
|
||||
var token = new HCaptchaTokenable(null)
|
||||
{
|
||||
var token = new HCaptchaTokenable(null);
|
||||
ExpirationDate = DateTime.UtcNow + TimeSpan.FromDays(1)
|
||||
};
|
||||
|
||||
Assert.Equal(default, token.Id);
|
||||
Assert.Equal(default, token.Email);
|
||||
}
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TokenWithNullUserIsInvalid()
|
||||
[Theory, BitAutoData]
|
||||
public void TokenValidityCheckNullUserIdIsInvalid(User user)
|
||||
{
|
||||
var token = new HCaptchaTokenable(user)
|
||||
{
|
||||
var token = new HCaptchaTokenable(null)
|
||||
{
|
||||
ExpirationDate = DateTime.UtcNow + TimeSpan.FromDays(1)
|
||||
};
|
||||
ExpirationDate = DateTime.UtcNow + TimeSpan.FromDays(1)
|
||||
};
|
||||
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
Assert.False(token.TokenIsValid(null));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void TokenValidityCheckNullUserIdIsInvalid(User user)
|
||||
[Theory, AutoData]
|
||||
public void CanUpdateExpirationToNonStandard(User user)
|
||||
{
|
||||
var token = new HCaptchaTokenable(user)
|
||||
{
|
||||
var token = new HCaptchaTokenable(user)
|
||||
{
|
||||
ExpirationDate = DateTime.UtcNow + TimeSpan.FromDays(1)
|
||||
};
|
||||
ExpirationDate = DateTime.MinValue
|
||||
};
|
||||
|
||||
Assert.False(token.TokenIsValid(null));
|
||||
}
|
||||
Assert.Equal(DateTime.MinValue, token.ExpirationDate, TimeSpan.FromMilliseconds(10));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public void CanUpdateExpirationToNonStandard(User user)
|
||||
[Theory, AutoData]
|
||||
public void SetsDataFromUser(User user)
|
||||
{
|
||||
var token = new HCaptchaTokenable(user);
|
||||
|
||||
Assert.Equal(user.Id, token.Id);
|
||||
Assert.Equal(user.Email, token.Email);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public void SerializationSetsCorrectDateTime(User user)
|
||||
{
|
||||
var expectedDateTime = DateTime.UtcNow.AddHours(-5);
|
||||
var token = new HCaptchaTokenable(user)
|
||||
{
|
||||
var token = new HCaptchaTokenable(user)
|
||||
{
|
||||
ExpirationDate = DateTime.MinValue
|
||||
};
|
||||
ExpirationDate = expectedDateTime
|
||||
};
|
||||
|
||||
Assert.Equal(DateTime.MinValue, token.ExpirationDate, TimeSpan.FromMilliseconds(10));
|
||||
}
|
||||
var result = Tokenable.FromToken<HCaptchaTokenable>(token.ToToken());
|
||||
|
||||
[Theory, AutoData]
|
||||
public void SetsDataFromUser(User user)
|
||||
Assert.Equal(expectedDateTime, result.ExpirationDate, TimeSpan.FromMilliseconds(10));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public void IsInvalidIfIdentifierIsWrong(User user)
|
||||
{
|
||||
var token = new HCaptchaTokenable(user)
|
||||
{
|
||||
var token = new HCaptchaTokenable(user);
|
||||
Identifier = "not correct"
|
||||
};
|
||||
|
||||
Assert.Equal(user.Id, token.Id);
|
||||
Assert.Equal(user.Email, token.Email);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public void SerializationSetsCorrectDateTime(User user)
|
||||
{
|
||||
var expectedDateTime = DateTime.UtcNow.AddHours(-5);
|
||||
var token = new HCaptchaTokenable(user)
|
||||
{
|
||||
ExpirationDate = expectedDateTime
|
||||
};
|
||||
|
||||
var result = Tokenable.FromToken<HCaptchaTokenable>(token.ToToken());
|
||||
|
||||
Assert.Equal(expectedDateTime, result.ExpirationDate, TimeSpan.FromMilliseconds(10));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public void IsInvalidIfIdentifierIsWrong(User user)
|
||||
{
|
||||
var token = new HCaptchaTokenable(user)
|
||||
{
|
||||
Identifier = "not correct"
|
||||
};
|
||||
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
}
|
||||
|
@ -4,153 +4,152 @@ using Bit.Core.Models.Business.Tokenables;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Models.Business.Tokenables
|
||||
namespace Bit.Core.Test.Models.Business.Tokenables;
|
||||
|
||||
public class OrganizationSponsorshipOfferTokenableTests
|
||||
{
|
||||
public class OrganizationSponsorshipOfferTokenableTests
|
||||
public static IEnumerable<object[]> PlanSponsorshipTypes() => Enum.GetValues<PlanSponsorshipType>().Select(x => new object[] { x });
|
||||
|
||||
[Fact]
|
||||
public void IsInvalidIfIdentifierIsWrong()
|
||||
{
|
||||
public static IEnumerable<object[]> PlanSponsorshipTypes() => Enum.GetValues<PlanSponsorshipType>().Select(x => new object[] { x });
|
||||
|
||||
[Fact]
|
||||
public void IsInvalidIfIdentifierIsWrong()
|
||||
var token = new OrganizationSponsorshipOfferTokenable()
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable()
|
||||
{
|
||||
Email = "email",
|
||||
Id = Guid.NewGuid(),
|
||||
Identifier = "not correct",
|
||||
SponsorshipType = PlanSponsorshipType.FamiliesForEnterprise,
|
||||
};
|
||||
Email = "email",
|
||||
Id = Guid.NewGuid(),
|
||||
Identifier = "not correct",
|
||||
SponsorshipType = PlanSponsorshipType.FamiliesForEnterprise,
|
||||
};
|
||||
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsInvalidIfIdIsDefault()
|
||||
[Fact]
|
||||
public void IsInvalidIfIdIsDefault()
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable()
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable()
|
||||
{
|
||||
Email = "email",
|
||||
Id = default,
|
||||
SponsorshipType = PlanSponsorshipType.FamiliesForEnterprise,
|
||||
};
|
||||
Email = "email",
|
||||
Id = default,
|
||||
SponsorshipType = PlanSponsorshipType.FamiliesForEnterprise,
|
||||
};
|
||||
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void IsInvalidIfEmailIsEmpty()
|
||||
[Fact]
|
||||
public void IsInvalidIfEmailIsEmpty()
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable()
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable()
|
||||
{
|
||||
Email = "",
|
||||
Id = Guid.NewGuid(),
|
||||
SponsorshipType = PlanSponsorshipType.FamiliesForEnterprise,
|
||||
};
|
||||
Email = "",
|
||||
Id = Guid.NewGuid(),
|
||||
SponsorshipType = PlanSponsorshipType.FamiliesForEnterprise,
|
||||
};
|
||||
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void IsValid_Success(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship);
|
||||
[Theory, BitAutoData]
|
||||
public void IsValid_Success(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship);
|
||||
|
||||
Assert.True(token.IsValid(sponsorship, sponsorship.OfferedToEmail));
|
||||
}
|
||||
Assert.True(token.IsValid(sponsorship, sponsorship.OfferedToEmail));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void IsValid_RequiresNonNullSponsorship(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship);
|
||||
[Theory, BitAutoData]
|
||||
public void IsValid_RequiresNonNullSponsorship(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship);
|
||||
|
||||
Assert.False(token.IsValid(null, sponsorship.OfferedToEmail));
|
||||
}
|
||||
Assert.False(token.IsValid(null, sponsorship.OfferedToEmail));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void IsValid_RequiresCurrentEmailToBeSameAsOfferedToEmail(OrganizationSponsorship sponsorship, string currentEmail)
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship);
|
||||
[Theory, BitAutoData]
|
||||
public void IsValid_RequiresCurrentEmailToBeSameAsOfferedToEmail(OrganizationSponsorship sponsorship, string currentEmail)
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship);
|
||||
|
||||
Assert.False(token.IsValid(sponsorship, currentEmail));
|
||||
}
|
||||
Assert.False(token.IsValid(sponsorship, currentEmail));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void IsValid_RequiresSameSponsorshipId(OrganizationSponsorship sponsorship1, OrganizationSponsorship sponsorship2)
|
||||
{
|
||||
sponsorship1.Id = sponsorship2.Id;
|
||||
[Theory, BitAutoData]
|
||||
public void IsValid_RequiresSameSponsorshipId(OrganizationSponsorship sponsorship1, OrganizationSponsorship sponsorship2)
|
||||
{
|
||||
sponsorship1.Id = sponsorship2.Id;
|
||||
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship1);
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship1);
|
||||
|
||||
Assert.False(token.IsValid(sponsorship2, sponsorship1.OfferedToEmail));
|
||||
}
|
||||
Assert.False(token.IsValid(sponsorship2, sponsorship1.OfferedToEmail));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void IsValid_RequiresSameEmail(OrganizationSponsorship sponsorship1, OrganizationSponsorship sponsorship2)
|
||||
{
|
||||
sponsorship1.OfferedToEmail = sponsorship2.OfferedToEmail;
|
||||
[Theory, BitAutoData]
|
||||
public void IsValid_RequiresSameEmail(OrganizationSponsorship sponsorship1, OrganizationSponsorship sponsorship2)
|
||||
{
|
||||
sponsorship1.OfferedToEmail = sponsorship2.OfferedToEmail;
|
||||
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship1);
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship1);
|
||||
|
||||
Assert.False(token.IsValid(sponsorship2, sponsorship1.OfferedToEmail));
|
||||
}
|
||||
Assert.False(token.IsValid(sponsorship2, sponsorship1.OfferedToEmail));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void Constructor_GrabsIdFromSponsorship(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship);
|
||||
[Theory, BitAutoData]
|
||||
public void Constructor_GrabsIdFromSponsorship(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship);
|
||||
|
||||
Assert.Equal(sponsorship.Id, token.Id);
|
||||
}
|
||||
Assert.Equal(sponsorship.Id, token.Id);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void Constructor_GrabsEmailFromSponsorshipOfferedToEmail(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship);
|
||||
[Theory, BitAutoData]
|
||||
public void Constructor_GrabsEmailFromSponsorshipOfferedToEmail(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship);
|
||||
|
||||
Assert.Equal(sponsorship.OfferedToEmail, token.Email);
|
||||
}
|
||||
Assert.Equal(sponsorship.OfferedToEmail, token.Email);
|
||||
}
|
||||
|
||||
[Theory, BitMemberAutoData(nameof(PlanSponsorshipTypes))]
|
||||
public void Constructor_GrabsSponsorshipType(PlanSponsorshipType planSponsorshipType,
|
||||
OrganizationSponsorship sponsorship)
|
||||
{
|
||||
sponsorship.PlanSponsorshipType = planSponsorshipType;
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship);
|
||||
[Theory, BitMemberAutoData(nameof(PlanSponsorshipTypes))]
|
||||
public void Constructor_GrabsSponsorshipType(PlanSponsorshipType planSponsorshipType,
|
||||
OrganizationSponsorship sponsorship)
|
||||
{
|
||||
sponsorship.PlanSponsorshipType = planSponsorshipType;
|
||||
var token = new OrganizationSponsorshipOfferTokenable(sponsorship);
|
||||
|
||||
Assert.Equal(sponsorship.PlanSponsorshipType, token.SponsorshipType);
|
||||
}
|
||||
Assert.Equal(sponsorship.PlanSponsorshipType, token.SponsorshipType);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void Constructor_DefaultId_Throws(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
sponsorship.Id = default;
|
||||
[Theory, BitAutoData]
|
||||
public void Constructor_DefaultId_Throws(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
sponsorship.Id = default;
|
||||
|
||||
Assert.Throws<ArgumentException>(() => new OrganizationSponsorshipOfferTokenable(sponsorship));
|
||||
}
|
||||
Assert.Throws<ArgumentException>(() => new OrganizationSponsorshipOfferTokenable(sponsorship));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void Constructor_NoOfferedToEmail_Throws(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
sponsorship.OfferedToEmail = null;
|
||||
[Theory, BitAutoData]
|
||||
public void Constructor_NoOfferedToEmail_Throws(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
sponsorship.OfferedToEmail = null;
|
||||
|
||||
Assert.Throws<ArgumentException>(() => new OrganizationSponsorshipOfferTokenable(sponsorship));
|
||||
}
|
||||
Assert.Throws<ArgumentException>(() => new OrganizationSponsorshipOfferTokenable(sponsorship));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void Constructor_EmptyOfferedToEmail_Throws(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
sponsorship.OfferedToEmail = "";
|
||||
[Theory, BitAutoData]
|
||||
public void Constructor_EmptyOfferedToEmail_Throws(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
sponsorship.OfferedToEmail = "";
|
||||
|
||||
Assert.Throws<ArgumentException>(() => new OrganizationSponsorshipOfferTokenable(sponsorship));
|
||||
}
|
||||
Assert.Throws<ArgumentException>(() => new OrganizationSponsorshipOfferTokenable(sponsorship));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void Constructor_NoPlanSponsorshipType_Throws(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
sponsorship.PlanSponsorshipType = null;
|
||||
[Theory, BitAutoData]
|
||||
public void Constructor_NoPlanSponsorshipType_Throws(OrganizationSponsorship sponsorship)
|
||||
{
|
||||
sponsorship.PlanSponsorshipType = null;
|
||||
|
||||
Assert.Throws<ArgumentException>(() => new OrganizationSponsorshipOfferTokenable(sponsorship));
|
||||
}
|
||||
Assert.Throws<ArgumentException>(() => new OrganizationSponsorshipOfferTokenable(sponsorship));
|
||||
}
|
||||
}
|
||||
|
@ -5,85 +5,84 @@ using Bit.Core.Tokens;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Models.Business.Tokenables
|
||||
namespace Bit.Core.Test.Models.Business.Tokenables;
|
||||
|
||||
public class SsoTokenableTests
|
||||
{
|
||||
public class SsoTokenableTests
|
||||
[Fact]
|
||||
public void CanHandleNullOrganization()
|
||||
{
|
||||
[Fact]
|
||||
public void CanHandleNullOrganization()
|
||||
var token = new SsoTokenable(null, default);
|
||||
|
||||
Assert.Equal(default, token.OrganizationId);
|
||||
Assert.Equal(default, token.DomainHint);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TokenWithNullOrganizationIsInvalid()
|
||||
{
|
||||
var token = new SsoTokenable(null, 500)
|
||||
{
|
||||
var token = new SsoTokenable(null, default);
|
||||
ExpirationDate = DateTime.UtcNow + TimeSpan.FromDays(1)
|
||||
};
|
||||
|
||||
Assert.Equal(default, token.OrganizationId);
|
||||
Assert.Equal(default, token.DomainHint);
|
||||
}
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TokenWithNullOrganizationIsInvalid()
|
||||
[Theory, BitAutoData]
|
||||
public void TokenValidityCheckNullOrganizationIsInvalid(Organization organization)
|
||||
{
|
||||
var token = new SsoTokenable(organization, 500)
|
||||
{
|
||||
var token = new SsoTokenable(null, 500)
|
||||
{
|
||||
ExpirationDate = DateTime.UtcNow + TimeSpan.FromDays(1)
|
||||
};
|
||||
ExpirationDate = DateTime.UtcNow + TimeSpan.FromDays(1)
|
||||
};
|
||||
|
||||
Assert.False(token.Valid);
|
||||
}
|
||||
Assert.False(token.TokenIsValid(null));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void TokenValidityCheckNullOrganizationIsInvalid(Organization organization)
|
||||
[Theory, AutoData]
|
||||
public void SetsDataFromOrganization(Organization organization)
|
||||
{
|
||||
var token = new SsoTokenable(organization, default);
|
||||
|
||||
Assert.Equal(organization.Id, token.OrganizationId);
|
||||
Assert.Equal(organization.Identifier, token.DomainHint);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetsExpirationFromConstructor()
|
||||
{
|
||||
var expectedDateTime = DateTime.UtcNow.AddSeconds(500);
|
||||
var token = new SsoTokenable(null, 500);
|
||||
|
||||
Assert.Equal(expectedDateTime, token.ExpirationDate, TimeSpan.FromMilliseconds(10));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public void SerializationSetsCorrectDateTime(Organization organization)
|
||||
{
|
||||
var expectedDateTime = DateTime.UtcNow.AddHours(-5);
|
||||
var token = new SsoTokenable(organization, default)
|
||||
{
|
||||
var token = new SsoTokenable(organization, 500)
|
||||
{
|
||||
ExpirationDate = DateTime.UtcNow + TimeSpan.FromDays(1)
|
||||
};
|
||||
ExpirationDate = expectedDateTime
|
||||
};
|
||||
|
||||
Assert.False(token.TokenIsValid(null));
|
||||
}
|
||||
var result = Tokenable.FromToken<HCaptchaTokenable>(token.ToToken());
|
||||
|
||||
[Theory, AutoData]
|
||||
public void SetsDataFromOrganization(Organization organization)
|
||||
Assert.Equal(expectedDateTime, result.ExpirationDate, TimeSpan.FromMilliseconds(10));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public void TokenIsValidFailsWhenExpired(Organization organization)
|
||||
{
|
||||
var expectedDateTime = DateTime.UtcNow.AddHours(-5);
|
||||
var token = new SsoTokenable(organization, default)
|
||||
{
|
||||
var token = new SsoTokenable(organization, default);
|
||||
ExpirationDate = expectedDateTime
|
||||
};
|
||||
|
||||
Assert.Equal(organization.Id, token.OrganizationId);
|
||||
Assert.Equal(organization.Identifier, token.DomainHint);
|
||||
}
|
||||
var result = token.TokenIsValid(organization);
|
||||
|
||||
[Fact]
|
||||
public void SetsExpirationFromConstructor()
|
||||
{
|
||||
var expectedDateTime = DateTime.UtcNow.AddSeconds(500);
|
||||
var token = new SsoTokenable(null, 500);
|
||||
|
||||
Assert.Equal(expectedDateTime, token.ExpirationDate, TimeSpan.FromMilliseconds(10));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public void SerializationSetsCorrectDateTime(Organization organization)
|
||||
{
|
||||
var expectedDateTime = DateTime.UtcNow.AddHours(-5);
|
||||
var token = new SsoTokenable(organization, default)
|
||||
{
|
||||
ExpirationDate = expectedDateTime
|
||||
};
|
||||
|
||||
var result = Tokenable.FromToken<HCaptchaTokenable>(token.ToToken());
|
||||
|
||||
Assert.Equal(expectedDateTime, result.ExpirationDate, TimeSpan.FromMilliseconds(10));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public void TokenIsValidFailsWhenExpired(Organization organization)
|
||||
{
|
||||
var expectedDateTime = DateTime.UtcNow.AddHours(-5);
|
||||
var token = new SsoTokenable(organization, default)
|
||||
{
|
||||
ExpirationDate = expectedDateTime
|
||||
};
|
||||
|
||||
var result = token.TokenIsValid(organization);
|
||||
|
||||
Assert.False(result);
|
||||
}
|
||||
Assert.False(result);
|
||||
}
|
||||
}
|
||||
|
@ -3,16 +3,15 @@ using Bit.Core.Entities;
|
||||
using Bit.Core.Test.AutoFixture.CipherFixtures;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Models
|
||||
namespace Bit.Core.Test.Models;
|
||||
|
||||
public class CipherTests
|
||||
{
|
||||
public class CipherTests
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData]
|
||||
[InlineOrganizationCipherAutoData]
|
||||
public void Clone_CreatesExactCopy(Cipher cipher)
|
||||
{
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData]
|
||||
[InlineOrganizationCipherAutoData]
|
||||
public void Clone_CreatesExactCopy(Cipher cipher)
|
||||
{
|
||||
Assert.Equal(JsonSerializer.Serialize(cipher), JsonSerializer.Serialize(cipher.Clone()));
|
||||
}
|
||||
Assert.Equal(JsonSerializer.Serialize(cipher), JsonSerializer.Serialize(cipher.Clone()));
|
||||
}
|
||||
}
|
||||
|
@ -3,26 +3,25 @@ using Bit.Core.Models.Data;
|
||||
using Bit.Test.Common.Helpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Models.Data
|
||||
{
|
||||
public class SendFileDataTests
|
||||
{
|
||||
[Fact]
|
||||
public void Serialize_Success()
|
||||
{
|
||||
var sut = new SendFileData
|
||||
{
|
||||
Id = "test",
|
||||
Size = 100,
|
||||
FileName = "thing.pdf",
|
||||
Validated = true,
|
||||
};
|
||||
namespace Bit.Core.Test.Models.Data;
|
||||
|
||||
var json = JsonSerializer.Serialize(sut);
|
||||
var document = JsonDocument.Parse(json);
|
||||
var root = document.RootElement;
|
||||
AssertHelper.AssertJsonProperty(root, "Size", JsonValueKind.String);
|
||||
Assert.False(root.TryGetProperty("SizeString", out _));
|
||||
}
|
||||
public class SendFileDataTests
|
||||
{
|
||||
[Fact]
|
||||
public void Serialize_Success()
|
||||
{
|
||||
var sut = new SendFileData
|
||||
{
|
||||
Id = "test",
|
||||
Size = 100,
|
||||
FileName = "thing.pdf",
|
||||
Validated = true,
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(sut);
|
||||
var document = JsonDocument.Parse(json);
|
||||
var root = document.RootElement;
|
||||
AssertHelper.AssertJsonProperty(root, "Size", JsonValueKind.String);
|
||||
Assert.False(root.TryGetProperty("SizeString", out _));
|
||||
}
|
||||
}
|
||||
|
@ -3,59 +3,58 @@ using Bit.Core.Models.Data;
|
||||
using Bit.Core.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Models
|
||||
namespace Bit.Core.Test.Models;
|
||||
|
||||
public class PermissionsTests
|
||||
{
|
||||
public class PermissionsTests
|
||||
private static readonly string _exampleSerializedPermissions = string.Concat(
|
||||
"{",
|
||||
"\"accessEventLogs\": false,",
|
||||
"\"accessImportExport\": false,",
|
||||
"\"accessReports\": false,",
|
||||
"\"manageAllCollections\": true,", // exists for backwards compatibility
|
||||
"\"createNewCollections\": true,",
|
||||
"\"editAnyCollection\": true,",
|
||||
"\"deleteAnyCollection\": true,",
|
||||
"\"manageAssignedCollections\": false,", // exists for backwards compatibility
|
||||
"\"editAssignedCollections\": false,",
|
||||
"\"deleteAssignedCollections\": false,",
|
||||
"\"manageGroups\": false,",
|
||||
"\"managePolicies\": false,",
|
||||
"\"manageSso\": false,",
|
||||
"\"manageUsers\": false,",
|
||||
"\"manageResetPassword\": false,",
|
||||
"\"manageScim\": false",
|
||||
"}");
|
||||
|
||||
[Fact]
|
||||
public void Serialization_Success()
|
||||
{
|
||||
private static readonly string _exampleSerializedPermissions = string.Concat(
|
||||
"{",
|
||||
"\"accessEventLogs\": false,",
|
||||
"\"accessImportExport\": false,",
|
||||
"\"accessReports\": false,",
|
||||
"\"manageAllCollections\": true,", // exists for backwards compatibility
|
||||
"\"createNewCollections\": true,",
|
||||
"\"editAnyCollection\": true,",
|
||||
"\"deleteAnyCollection\": true,",
|
||||
"\"manageAssignedCollections\": false,", // exists for backwards compatibility
|
||||
"\"editAssignedCollections\": false,",
|
||||
"\"deleteAssignedCollections\": false,",
|
||||
"\"manageGroups\": false,",
|
||||
"\"managePolicies\": false,",
|
||||
"\"manageSso\": false,",
|
||||
"\"manageUsers\": false,",
|
||||
"\"manageResetPassword\": false,",
|
||||
"\"manageScim\": false",
|
||||
"}");
|
||||
|
||||
[Fact]
|
||||
public void Serialization_Success()
|
||||
var permissions = new Permissions
|
||||
{
|
||||
var permissions = new Permissions
|
||||
{
|
||||
AccessEventLogs = false,
|
||||
AccessImportExport = false,
|
||||
AccessReports = false,
|
||||
CreateNewCollections = true,
|
||||
EditAnyCollection = true,
|
||||
DeleteAnyCollection = true,
|
||||
EditAssignedCollections = false,
|
||||
DeleteAssignedCollections = false,
|
||||
ManageGroups = false,
|
||||
ManagePolicies = false,
|
||||
ManageSso = false,
|
||||
ManageUsers = false,
|
||||
ManageResetPassword = false,
|
||||
ManageScim = false,
|
||||
};
|
||||
AccessEventLogs = false,
|
||||
AccessImportExport = false,
|
||||
AccessReports = false,
|
||||
CreateNewCollections = true,
|
||||
EditAnyCollection = true,
|
||||
DeleteAnyCollection = true,
|
||||
EditAssignedCollections = false,
|
||||
DeleteAssignedCollections = false,
|
||||
ManageGroups = false,
|
||||
ManagePolicies = false,
|
||||
ManageSso = false,
|
||||
ManageUsers = false,
|
||||
ManageResetPassword = false,
|
||||
ManageScim = false,
|
||||
};
|
||||
|
||||
// minify expected json
|
||||
var expected = JsonSerializer.Serialize(permissions, JsonHelpers.CamelCase);
|
||||
// minify expected json
|
||||
var expected = JsonSerializer.Serialize(permissions, JsonHelpers.CamelCase);
|
||||
|
||||
var actual = JsonSerializer.Serialize(
|
||||
JsonHelpers.DeserializeOrNew<Permissions>(_exampleSerializedPermissions, JsonHelpers.CamelCase),
|
||||
JsonHelpers.CamelCase);
|
||||
var actual = JsonSerializer.Serialize(
|
||||
JsonHelpers.DeserializeOrNew<Permissions>(_exampleSerializedPermissions, JsonHelpers.CamelCase),
|
||||
JsonHelpers.CamelCase);
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
|
@ -7,94 +7,93 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationApiKeys
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationApiKeys;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class GetOrganizationApiKeyCommandTests
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
public class GetOrganizationApiKeyCommandTests
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetOrganizationApiKey_HasOne_Returns(SutProvider<GetOrganizationApiKeyCommand> sutProvider,
|
||||
Guid id, Guid organizationId, OrganizationApiKeyType keyType)
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetOrganizationApiKey_HasOne_Returns(SutProvider<GetOrganizationApiKeyCommand> sutProvider,
|
||||
Guid id, Guid organizationId, OrganizationApiKeyType keyType)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationApiKeyRepository>()
|
||||
.GetManyByOrganizationIdTypeAsync(organizationId, keyType)
|
||||
.Returns(new List<OrganizationApiKey>
|
||||
sutProvider.GetDependency<IOrganizationApiKeyRepository>()
|
||||
.GetManyByOrganizationIdTypeAsync(organizationId, keyType)
|
||||
.Returns(new List<OrganizationApiKey>
|
||||
{
|
||||
new OrganizationApiKey
|
||||
{
|
||||
new OrganizationApiKey
|
||||
{
|
||||
Id = id,
|
||||
OrganizationId = organizationId,
|
||||
ApiKey = "test",
|
||||
Type = keyType,
|
||||
RevisionDate = DateTime.Now.AddDays(-1),
|
||||
},
|
||||
});
|
||||
Id = id,
|
||||
OrganizationId = organizationId,
|
||||
ApiKey = "test",
|
||||
Type = keyType,
|
||||
RevisionDate = DateTime.Now.AddDays(-1),
|
||||
},
|
||||
});
|
||||
|
||||
var apiKey = await sutProvider.Sut.GetOrganizationApiKeyAsync(organizationId, keyType);
|
||||
Assert.NotNull(apiKey);
|
||||
Assert.Equal(id, apiKey.Id);
|
||||
}
|
||||
var apiKey = await sutProvider.Sut.GetOrganizationApiKeyAsync(organizationId, keyType);
|
||||
Assert.NotNull(apiKey);
|
||||
Assert.Equal(id, apiKey.Id);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetOrganizationApiKey_HasTwo_Throws(SutProvider<GetOrganizationApiKeyCommand> sutProvider,
|
||||
Guid organizationId, OrganizationApiKeyType keyType)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationApiKeyRepository>()
|
||||
.GetManyByOrganizationIdTypeAsync(organizationId, keyType)
|
||||
.Returns(new List<OrganizationApiKey>
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetOrganizationApiKey_HasTwo_Throws(SutProvider<GetOrganizationApiKeyCommand> sutProvider,
|
||||
Guid organizationId, OrganizationApiKeyType keyType)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationApiKeyRepository>()
|
||||
.GetManyByOrganizationIdTypeAsync(organizationId, keyType)
|
||||
.Returns(new List<OrganizationApiKey>
|
||||
{
|
||||
new OrganizationApiKey
|
||||
{
|
||||
new OrganizationApiKey
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
OrganizationId = organizationId,
|
||||
ApiKey = "test",
|
||||
Type = keyType,
|
||||
RevisionDate = DateTime.Now.AddDays(-1),
|
||||
},
|
||||
new OrganizationApiKey
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
OrganizationId = organizationId,
|
||||
ApiKey = "test_other",
|
||||
Type = keyType,
|
||||
RevisionDate = DateTime.Now.AddDays(-1),
|
||||
},
|
||||
});
|
||||
Id = Guid.NewGuid(),
|
||||
OrganizationId = organizationId,
|
||||
ApiKey = "test",
|
||||
Type = keyType,
|
||||
RevisionDate = DateTime.Now.AddDays(-1),
|
||||
},
|
||||
new OrganizationApiKey
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
OrganizationId = organizationId,
|
||||
ApiKey = "test_other",
|
||||
Type = keyType,
|
||||
RevisionDate = DateTime.Now.AddDays(-1),
|
||||
},
|
||||
});
|
||||
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
async () => await sutProvider.Sut.GetOrganizationApiKeyAsync(organizationId, keyType));
|
||||
}
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
async () => await sutProvider.Sut.GetOrganizationApiKeyAsync(organizationId, keyType));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetOrganizationApiKey_HasNone_CreatesAndReturns(SutProvider<GetOrganizationApiKeyCommand> sutProvider,
|
||||
Guid organizationId, OrganizationApiKeyType keyType)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationApiKeyRepository>()
|
||||
.GetManyByOrganizationIdTypeAsync(organizationId, keyType)
|
||||
.Returns(Enumerable.Empty<OrganizationApiKey>());
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetOrganizationApiKey_HasNone_CreatesAndReturns(SutProvider<GetOrganizationApiKeyCommand> sutProvider,
|
||||
Guid organizationId, OrganizationApiKeyType keyType)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationApiKeyRepository>()
|
||||
.GetManyByOrganizationIdTypeAsync(organizationId, keyType)
|
||||
.Returns(Enumerable.Empty<OrganizationApiKey>());
|
||||
|
||||
var apiKey = await sutProvider.Sut.GetOrganizationApiKeyAsync(organizationId, keyType);
|
||||
var apiKey = await sutProvider.Sut.GetOrganizationApiKeyAsync(organizationId, keyType);
|
||||
|
||||
Assert.NotNull(apiKey);
|
||||
Assert.Equal(organizationId, apiKey.OrganizationId);
|
||||
Assert.Equal(keyType, apiKey.Type);
|
||||
await sutProvider.GetDependency<IOrganizationApiKeyRepository>()
|
||||
.Received(1)
|
||||
.CreateAsync(Arg.Any<OrganizationApiKey>());
|
||||
}
|
||||
Assert.NotNull(apiKey);
|
||||
Assert.Equal(organizationId, apiKey.OrganizationId);
|
||||
Assert.Equal(keyType, apiKey.Type);
|
||||
await sutProvider.GetDependency<IOrganizationApiKeyRepository>()
|
||||
.Received(1)
|
||||
.CreateAsync(Arg.Any<OrganizationApiKey>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetOrganizationApiKey_BadType_Throws(SutProvider<GetOrganizationApiKeyCommand> sutProvider,
|
||||
Guid organizationId, OrganizationApiKeyType keyType)
|
||||
{
|
||||
keyType = (OrganizationApiKeyType)byte.MaxValue;
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetOrganizationApiKey_BadType_Throws(SutProvider<GetOrganizationApiKeyCommand> sutProvider,
|
||||
Guid organizationId, OrganizationApiKeyType keyType)
|
||||
{
|
||||
keyType = (OrganizationApiKeyType)byte.MaxValue;
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(
|
||||
async () => await sutProvider.Sut.GetOrganizationApiKeyAsync(organizationId, keyType));
|
||||
}
|
||||
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(
|
||||
async () => await sutProvider.Sut.GetOrganizationApiKeyAsync(organizationId, keyType));
|
||||
}
|
||||
}
|
||||
|
@ -5,19 +5,18 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Bit.Test.Common.Helpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationApiKeys
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationApiKeys;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class RotateOrganizationApiKeyCommandTests
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
public class RotateOrganizationApiKeyCommandTests
|
||||
[Theory, BitAutoData]
|
||||
public async Task RotateApiKeyAsync_RotatesKey(SutProvider<RotateOrganizationApiKeyCommand> sutProvider,
|
||||
OrganizationApiKey organizationApiKey)
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
public async Task RotateApiKeyAsync_RotatesKey(SutProvider<RotateOrganizationApiKeyCommand> sutProvider,
|
||||
OrganizationApiKey organizationApiKey)
|
||||
{
|
||||
var existingKey = organizationApiKey.ApiKey;
|
||||
organizationApiKey = await sutProvider.Sut.RotateApiKeyAsync(organizationApiKey);
|
||||
Assert.NotEqual(existingKey, organizationApiKey.ApiKey);
|
||||
AssertHelper.AssertRecent(organizationApiKey.RevisionDate);
|
||||
}
|
||||
var existingKey = organizationApiKey.ApiKey;
|
||||
organizationApiKey = await sutProvider.Sut.RotateApiKeyAsync(organizationApiKey);
|
||||
Assert.NotEqual(existingKey, organizationApiKey.ApiKey);
|
||||
AssertHelper.AssertRecent(organizationApiKey.RevisionDate);
|
||||
}
|
||||
}
|
||||
|
@ -8,20 +8,19 @@ using Bit.Test.Common.Helpers;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationConnections
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
public class CreateOrganizationConnectionCommandTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CreateAsync_CallsCreate(OrganizationConnectionData<BillingSyncConfig> data,
|
||||
SutProvider<CreateOrganizationConnectionCommand> sutProvider)
|
||||
{
|
||||
await sutProvider.Sut.CreateAsync(data);
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationConnections;
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationConnectionRepository>().Received(1)
|
||||
.CreateAsync(Arg.Is(AssertHelper.AssertPropertyEqual(data.ToEntity())));
|
||||
}
|
||||
[SutProviderCustomize]
|
||||
public class CreateOrganizationConnectionCommandTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CreateAsync_CallsCreate(OrganizationConnectionData<BillingSyncConfig> data,
|
||||
SutProvider<CreateOrganizationConnectionCommand> sutProvider)
|
||||
{
|
||||
await sutProvider.Sut.CreateAsync(data);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationConnectionRepository>().Received(1)
|
||||
.CreateAsync(Arg.Is(AssertHelper.AssertPropertyEqual(data.ToEntity())));
|
||||
}
|
||||
}
|
||||
|
@ -6,20 +6,19 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationConnections
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
public class DeleteOrganizationConnectionCommandTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task DeleteAsync_CallsDelete(OrganizationConnection connection,
|
||||
SutProvider<DeleteOrganizationConnectionCommand> sutProvider)
|
||||
{
|
||||
await sutProvider.Sut.DeleteAsync(connection);
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationConnections;
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationConnectionRepository>().Received(1)
|
||||
.DeleteAsync(connection);
|
||||
}
|
||||
[SutProviderCustomize]
|
||||
public class DeleteOrganizationConnectionCommandTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task DeleteAsync_CallsDelete(OrganizationConnection connection,
|
||||
SutProvider<DeleteOrganizationConnectionCommand> sutProvider)
|
||||
{
|
||||
await sutProvider.Sut.DeleteAsync(connection);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationConnectionRepository>().Received(1)
|
||||
.DeleteAsync(connection);
|
||||
}
|
||||
}
|
||||
|
@ -10,50 +10,49 @@ using Bit.Test.Common.Helpers;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationConnections
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationConnections;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class UpdateOrganizationConnectionCommandTests
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
public class UpdateOrganizationConnectionCommandTests
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateAsync_NoId_Fails(OrganizationConnectionData<BillingSyncConfig> data,
|
||||
SutProvider<UpdateOrganizationConnectionCommand> sutProvider)
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateAsync_NoId_Fails(OrganizationConnectionData<BillingSyncConfig> data,
|
||||
SutProvider<UpdateOrganizationConnectionCommand> sutProvider)
|
||||
{
|
||||
data.Id = null;
|
||||
data.Id = null;
|
||||
|
||||
var exception = await Assert.ThrowsAsync<Exception>(() => sutProvider.Sut.UpdateAsync(data));
|
||||
var exception = await Assert.ThrowsAsync<Exception>(() => sutProvider.Sut.UpdateAsync(data));
|
||||
|
||||
Assert.Contains("Cannot update connection, Connection does not exist.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationConnectionRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
Assert.Contains("Cannot update connection, Connection does not exist.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationConnectionRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateAsync_ConnectionDoesNotExist_ThrowsNotFound(
|
||||
OrganizationConnectionData<BillingSyncConfig> data,
|
||||
SutProvider<UpdateOrganizationConnectionCommand> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.UpdateAsync(data));
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateAsync_ConnectionDoesNotExist_ThrowsNotFound(
|
||||
OrganizationConnectionData<BillingSyncConfig> data,
|
||||
SutProvider<UpdateOrganizationConnectionCommand> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.UpdateAsync(data));
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationConnectionRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
await sutProvider.GetDependency<IOrganizationConnectionRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateAsync_CallsUpsert(OrganizationConnectionData<BillingSyncConfig> data,
|
||||
OrganizationConnection existing,
|
||||
SutProvider<UpdateOrganizationConnectionCommand> sutProvider)
|
||||
{
|
||||
data.Id = existing.Id;
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateAsync_CallsUpsert(OrganizationConnectionData<BillingSyncConfig> data,
|
||||
OrganizationConnection existing,
|
||||
SutProvider<UpdateOrganizationConnectionCommand> sutProvider)
|
||||
{
|
||||
data.Id = existing.Id;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>().GetByIdAsync(data.Id.Value).Returns(existing);
|
||||
await sutProvider.Sut.UpdateAsync(data);
|
||||
sutProvider.GetDependency<IOrganizationConnectionRepository>().GetByIdAsync(data.Id.Value).Returns(existing);
|
||||
await sutProvider.Sut.UpdateAsync(data);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationConnectionRepository>().Received(1)
|
||||
.UpsertAsync(Arg.Is(AssertHelper.AssertPropertyEqual(data.ToEntity())));
|
||||
}
|
||||
await sutProvider.GetDependency<IOrganizationConnectionRepository>().Received(1)
|
||||
.UpsertAsync(Arg.Is(AssertHelper.AssertPropertyEqual(data.ToEntity())));
|
||||
}
|
||||
}
|
||||
|
@ -4,71 +4,70 @@ using Bit.Core.Services;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using NSubstitute;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise;
|
||||
|
||||
public abstract class CancelSponsorshipCommandTestsBase : FamiliesForEnterpriseTestsBase
|
||||
{
|
||||
public abstract class CancelSponsorshipCommandTestsBase : FamiliesForEnterpriseTestsBase
|
||||
protected async Task AssertRemovedSponsoredPaymentAsync<T>(Organization sponsoredOrg,
|
||||
OrganizationSponsorship sponsorship, SutProvider<T> sutProvider)
|
||||
{
|
||||
protected async Task AssertRemovedSponsoredPaymentAsync<T>(Organization sponsoredOrg,
|
||||
OrganizationSponsorship sponsorship, SutProvider<T> sutProvider)
|
||||
await sutProvider.GetDependency<IPaymentService>().Received(1)
|
||||
.RemoveOrganizationSponsorshipAsync(sponsoredOrg, sponsorship);
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().Received(1).UpsertAsync(sponsoredOrg);
|
||||
if (sponsorship != null)
|
||||
{
|
||||
await sutProvider.GetDependency<IPaymentService>().Received(1)
|
||||
.RemoveOrganizationSponsorshipAsync(sponsoredOrg, sponsorship);
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().Received(1).UpsertAsync(sponsoredOrg);
|
||||
if (sponsorship != null)
|
||||
{
|
||||
await sutProvider.GetDependency<IMailService>().Received(1)
|
||||
.SendFamiliesForEnterpriseSponsorshipRevertingEmailAsync(sponsoredOrg.BillingEmailAddress(), sponsorship.ValidUntil.GetValueOrDefault());
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task AssertDeletedSponsorshipAsync<T>(OrganizationSponsorship sponsorship,
|
||||
SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().Received(1)
|
||||
.DeleteAsync(sponsorship);
|
||||
}
|
||||
|
||||
protected static async Task AssertDidNotRemoveSponsorshipAsync<T>(SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.DeleteAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
protected async Task AssertRemovedSponsorshipAsync<T>(OrganizationSponsorship sponsorship,
|
||||
SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().Received(1)
|
||||
.DeleteAsync(sponsorship);
|
||||
}
|
||||
|
||||
protected static async Task AssertDidNotRemoveSponsoredPaymentAsync<T>(SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IPaymentService>().DidNotReceiveWithAnyArgs()
|
||||
.RemoveOrganizationSponsorshipAsync(default, default);
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
await sutProvider.GetDependency<IMailService>().DidNotReceiveWithAnyArgs()
|
||||
.SendFamiliesForEnterpriseSponsorshipRevertingEmailAsync(default, default);
|
||||
}
|
||||
|
||||
protected static async Task AssertDidNotDeleteSponsorshipAsync<T>(SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.DeleteAsync(default);
|
||||
}
|
||||
|
||||
protected static async Task AssertDidNotUpdateSponsorshipAsync<T>(SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
protected static async Task AssertUpdatedSponsorshipAsync<T>(OrganizationSponsorship sponsorship,
|
||||
SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().Received(1).UpsertAsync(sponsorship);
|
||||
await sutProvider.GetDependency<IMailService>().Received(1)
|
||||
.SendFamiliesForEnterpriseSponsorshipRevertingEmailAsync(sponsoredOrg.BillingEmailAddress(), sponsorship.ValidUntil.GetValueOrDefault());
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task AssertDeletedSponsorshipAsync<T>(OrganizationSponsorship sponsorship,
|
||||
SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().Received(1)
|
||||
.DeleteAsync(sponsorship);
|
||||
}
|
||||
|
||||
protected static async Task AssertDidNotRemoveSponsorshipAsync<T>(SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.DeleteAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
protected async Task AssertRemovedSponsorshipAsync<T>(OrganizationSponsorship sponsorship,
|
||||
SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().Received(1)
|
||||
.DeleteAsync(sponsorship);
|
||||
}
|
||||
|
||||
protected static async Task AssertDidNotRemoveSponsoredPaymentAsync<T>(SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IPaymentService>().DidNotReceiveWithAnyArgs()
|
||||
.RemoveOrganizationSponsorshipAsync(default, default);
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
await sutProvider.GetDependency<IMailService>().DidNotReceiveWithAnyArgs()
|
||||
.SendFamiliesForEnterpriseSponsorshipRevertingEmailAsync(default, default);
|
||||
}
|
||||
|
||||
protected static async Task AssertDidNotDeleteSponsorshipAsync<T>(SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.DeleteAsync(default);
|
||||
}
|
||||
|
||||
protected static async Task AssertDidNotUpdateSponsorshipAsync<T>(SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
protected static async Task AssertUpdatedSponsorshipAsync<T>(OrganizationSponsorship sponsorship,
|
||||
SutProvider<T> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().Received(1).UpsertAsync(sponsorship);
|
||||
}
|
||||
}
|
||||
|
@ -6,46 +6,45 @@ using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud;
|
||||
|
||||
[SutProviderCustomize]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
public class CloudRevokeSponsorshipCommandTests : CancelSponsorshipCommandTestsBase
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
public class CloudRevokeSponsorshipCommandTests : CancelSponsorshipCommandTestsBase
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_NoExistingSponsorship_ThrowsBadRequest(
|
||||
SutProvider<CloudRevokeSponsorshipCommand> sutProvider)
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_NoExistingSponsorship_ThrowsBadRequest(
|
||||
SutProvider<CloudRevokeSponsorshipCommand> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RevokeSponsorshipAsync(null));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RevokeSponsorshipAsync(null));
|
||||
|
||||
Assert.Contains("You are not currently sponsoring an organization.", exception.Message);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
await AssertDidNotUpdateSponsorshipAsync(sutProvider);
|
||||
}
|
||||
Assert.Contains("You are not currently sponsoring an organization.", exception.Message);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
await AssertDidNotUpdateSponsorshipAsync(sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_SponsorshipNotRedeemed_DeletesSponsorship(OrganizationSponsorship sponsorship,
|
||||
SutProvider<CloudRevokeSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsorship.SponsoredOrganizationId = null;
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_SponsorshipNotRedeemed_DeletesSponsorship(OrganizationSponsorship sponsorship,
|
||||
SutProvider<CloudRevokeSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsorship.SponsoredOrganizationId = null;
|
||||
|
||||
await sutProvider.Sut.RevokeSponsorshipAsync(sponsorship);
|
||||
await AssertDeletedSponsorshipAsync(sponsorship, sutProvider);
|
||||
}
|
||||
await sutProvider.Sut.RevokeSponsorshipAsync(sponsorship);
|
||||
await AssertDeletedSponsorshipAsync(sponsorship, sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_SponsorshipRedeemed_MarksForDelete(OrganizationSponsorship sponsorship,
|
||||
SutProvider<CloudRevokeSponsorshipCommand> sutProvider)
|
||||
{
|
||||
await sutProvider.Sut.RevokeSponsorshipAsync(sponsorship);
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_SponsorshipRedeemed_MarksForDelete(OrganizationSponsorship sponsorship,
|
||||
SutProvider<CloudRevokeSponsorshipCommand> sutProvider)
|
||||
{
|
||||
await sutProvider.Sut.RevokeSponsorshipAsync(sponsorship);
|
||||
|
||||
Assert.True(sponsorship.ToDelete);
|
||||
await AssertUpdatedSponsorshipAsync(sponsorship, sutProvider);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
}
|
||||
Assert.True(sponsorship.ToDelete);
|
||||
await AssertUpdatedSponsorshipAsync(sponsorship, sutProvider);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
}
|
||||
}
|
||||
|
@ -10,218 +10,216 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class CloudSyncSponsorshipsCommandTests : FamiliesForEnterpriseTestsBase
|
||||
{
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class CloudSyncSponsorshipsCommandTests : FamiliesForEnterpriseTestsBase
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_SponsoringOrgNotFound_ThrowsBadRequest(
|
||||
IEnumerable<OrganizationSponsorshipData> sponsorshipsData,
|
||||
SutProvider<CloudSyncSponsorshipsCommand> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SyncOrganization(null, sponsorshipsData));
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_SponsoringOrgNotFound_ThrowsBadRequest(
|
||||
IEnumerable<OrganizationSponsorshipData> sponsorshipsData,
|
||||
SutProvider<CloudSyncSponsorshipsCommand> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SyncOrganization(null, sponsorshipsData));
|
||||
Assert.Contains("Failed to sync sponsorship - missing organization.", exception.Message);
|
||||
|
||||
Assert.Contains("Failed to sync sponsorship - missing organization.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
}
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
}
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_NoSponsorships_EarlyReturn(
|
||||
Organization organization,
|
||||
SutProvider<CloudSyncSponsorshipsCommand> sutProvider)
|
||||
{
|
||||
var result = await sutProvider.Sut.SyncOrganization(organization, Enumerable.Empty<OrganizationSponsorshipData>());
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_NoSponsorships_EarlyReturn(
|
||||
Organization organization,
|
||||
SutProvider<CloudSyncSponsorshipsCommand> sutProvider)
|
||||
{
|
||||
var result = await sutProvider.Sut.SyncOrganization(organization, Enumerable.Empty<OrganizationSponsorshipData>());
|
||||
Assert.Empty(result.Item1.SponsorshipsBatch);
|
||||
Assert.Empty(result.Item2);
|
||||
|
||||
Assert.Empty(result.Item1.SponsorshipsBatch);
|
||||
Assert.Empty(result.Item2);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
}
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
}
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(NonEnterprisePlanTypes))]
|
||||
public async Task SyncOrganization_BadSponsoringOrgPlan_NoSync(
|
||||
PlanType planType,
|
||||
Organization organization, IEnumerable<OrganizationSponsorshipData> sponsorshipsData,
|
||||
SutProvider<CloudSyncSponsorshipsCommand> sutProvider)
|
||||
{
|
||||
organization.PlanType = planType;
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(NonEnterprisePlanTypes))]
|
||||
public async Task SyncOrganization_BadSponsoringOrgPlan_NoSync(
|
||||
PlanType planType,
|
||||
Organization organization, IEnumerable<OrganizationSponsorshipData> sponsorshipsData,
|
||||
SutProvider<CloudSyncSponsorshipsCommand> sutProvider)
|
||||
{
|
||||
organization.PlanType = planType;
|
||||
await sutProvider.Sut.SyncOrganization(organization, sponsorshipsData);
|
||||
|
||||
await sutProvider.Sut.SyncOrganization(organization, sponsorshipsData);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
}
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
}
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_Success_RecordsEvent(Organization organization,
|
||||
SutProvider<CloudSyncSponsorshipsCommand> sutProvider)
|
||||
{
|
||||
await sutProvider.Sut.SyncOrganization(organization, Array.Empty<OrganizationSponsorshipData>());
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_Success_RecordsEvent(Organization organization,
|
||||
SutProvider<CloudSyncSponsorshipsCommand> sutProvider)
|
||||
{
|
||||
await sutProvider.Sut.SyncOrganization(organization, Array.Empty<OrganizationSponsorshipData>());
|
||||
await sutProvider.GetDependency<IEventService>().Received(1).LogOrganizationEventAsync(organization, EventType.Organization_SponsorshipsSynced, Arg.Any<DateTime?>());
|
||||
}
|
||||
|
||||
await sutProvider.GetDependency<IEventService>().Received(1).LogOrganizationEventAsync(organization, EventType.Organization_SponsorshipsSynced, Arg.Any<DateTime?>());
|
||||
}
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_OneExisting_OneNew_Success(SutProvider<CloudSyncSponsorshipsCommand> sutProvider,
|
||||
Organization sponsoringOrganization, OrganizationSponsorship existingSponsorship, OrganizationSponsorship newSponsorship)
|
||||
{
|
||||
// Arrange
|
||||
sponsoringOrganization.Enabled = true;
|
||||
sponsoringOrganization.PlanType = PlanType.EnterpriseAnnually;
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_OneExisting_OneNew_Success(SutProvider<CloudSyncSponsorshipsCommand> sutProvider,
|
||||
Organization sponsoringOrganization, OrganizationSponsorship existingSponsorship, OrganizationSponsorship newSponsorship)
|
||||
{
|
||||
// Arrange
|
||||
sponsoringOrganization.Enabled = true;
|
||||
sponsoringOrganization.PlanType = PlanType.EnterpriseAnnually;
|
||||
existingSponsorship.ToDelete = false;
|
||||
newSponsorship.ToDelete = false;
|
||||
|
||||
existingSponsorship.ToDelete = false;
|
||||
newSponsorship.ToDelete = false;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetManyBySponsoringOrganizationAsync(sponsoringOrganization.Id)
|
||||
.Returns(new List<OrganizationSponsorship>
|
||||
{
|
||||
existingSponsorship,
|
||||
});
|
||||
|
||||
// Act
|
||||
var (syncData, toEmailSponsorships) = await sutProvider.Sut.SyncOrganization(sponsoringOrganization, new[]
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetManyBySponsoringOrganizationAsync(sponsoringOrganization.Id)
|
||||
.Returns(new List<OrganizationSponsorship>
|
||||
{
|
||||
new OrganizationSponsorshipData(existingSponsorship),
|
||||
new OrganizationSponsorshipData(newSponsorship),
|
||||
existingSponsorship,
|
||||
});
|
||||
|
||||
// Assert
|
||||
// Should have updated the cloud copy for each item given
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.Received(1)
|
||||
.UpsertManyAsync(Arg.Is<IEnumerable<OrganizationSponsorship>>(sponsorships => sponsorships.Count() == 2));
|
||||
|
||||
// Neither were marked as delete, should not have deleted
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
|
||||
// Only one sponsorship was new so it should only send one
|
||||
Assert.Single(toEmailSponsorships);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_TwoToDelete_OneCanDelete_Success(SutProvider<CloudSyncSponsorshipsCommand> sutProvider,
|
||||
Organization sponsoringOrganization, OrganizationSponsorship canDeleteSponsorship, OrganizationSponsorship cannotDeleteSponsorship)
|
||||
// Act
|
||||
var (syncData, toEmailSponsorships) = await sutProvider.Sut.SyncOrganization(sponsoringOrganization, new[]
|
||||
{
|
||||
// Arrange
|
||||
sponsoringOrganization.PlanType = PlanType.EnterpriseAnnually;
|
||||
new OrganizationSponsorshipData(existingSponsorship),
|
||||
new OrganizationSponsorshipData(newSponsorship),
|
||||
});
|
||||
|
||||
canDeleteSponsorship.ToDelete = true;
|
||||
canDeleteSponsorship.SponsoredOrganizationId = null;
|
||||
// Assert
|
||||
// Should have updated the cloud copy for each item given
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.Received(1)
|
||||
.UpsertManyAsync(Arg.Is<IEnumerable<OrganizationSponsorship>>(sponsorships => sponsorships.Count() == 2));
|
||||
|
||||
cannotDeleteSponsorship.ToDelete = true;
|
||||
cannotDeleteSponsorship.SponsoredOrganizationId = Guid.NewGuid();
|
||||
// Neither were marked as delete, should not have deleted
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetManyBySponsoringOrganizationAsync(sponsoringOrganization.Id)
|
||||
.Returns(new List<OrganizationSponsorship>
|
||||
{
|
||||
canDeleteSponsorship,
|
||||
cannotDeleteSponsorship,
|
||||
});
|
||||
// Only one sponsorship was new so it should only send one
|
||||
Assert.Single(toEmailSponsorships);
|
||||
}
|
||||
|
||||
// Act
|
||||
var (syncData, toEmailSponsorships) = await sutProvider.Sut.SyncOrganization(sponsoringOrganization, new[]
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_TwoToDelete_OneCanDelete_Success(SutProvider<CloudSyncSponsorshipsCommand> sutProvider,
|
||||
Organization sponsoringOrganization, OrganizationSponsorship canDeleteSponsorship, OrganizationSponsorship cannotDeleteSponsorship)
|
||||
{
|
||||
// Arrange
|
||||
sponsoringOrganization.PlanType = PlanType.EnterpriseAnnually;
|
||||
|
||||
canDeleteSponsorship.ToDelete = true;
|
||||
canDeleteSponsorship.SponsoredOrganizationId = null;
|
||||
|
||||
cannotDeleteSponsorship.ToDelete = true;
|
||||
cannotDeleteSponsorship.SponsoredOrganizationId = Guid.NewGuid();
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetManyBySponsoringOrganizationAsync(sponsoringOrganization.Id)
|
||||
.Returns(new List<OrganizationSponsorship>
|
||||
{
|
||||
new OrganizationSponsorshipData(canDeleteSponsorship),
|
||||
new OrganizationSponsorshipData(cannotDeleteSponsorship),
|
||||
canDeleteSponsorship,
|
||||
cannotDeleteSponsorship,
|
||||
});
|
||||
|
||||
// Assert
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.Received(1)
|
||||
.UpsertManyAsync(Arg.Is<IEnumerable<OrganizationSponsorship>>(sponsorships => sponsorships.Count() == 2));
|
||||
|
||||
// Deletes the sponsorship that had delete requested and is not sponsoring an org
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.Received(1)
|
||||
.DeleteManyAsync(Arg.Is<IEnumerable<Guid>>(toDeleteIds =>
|
||||
toDeleteIds.Count() == 1 && toDeleteIds.ElementAt(0) == canDeleteSponsorship.Id));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_BadData_DoesNotSave(SutProvider<CloudSyncSponsorshipsCommand> sutProvider,
|
||||
Organization sponsoringOrganization, OrganizationSponsorship badOrganizationSponsorship)
|
||||
// Act
|
||||
var (syncData, toEmailSponsorships) = await sutProvider.Sut.SyncOrganization(sponsoringOrganization, new[]
|
||||
{
|
||||
sponsoringOrganization.PlanType = PlanType.EnterpriseAnnually;
|
||||
new OrganizationSponsorshipData(canDeleteSponsorship),
|
||||
new OrganizationSponsorshipData(cannotDeleteSponsorship),
|
||||
});
|
||||
|
||||
badOrganizationSponsorship.ToDelete = true;
|
||||
badOrganizationSponsorship.LastSyncDate = null;
|
||||
// Assert
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetManyBySponsoringOrganizationAsync(sponsoringOrganization.Id)
|
||||
.Returns(new List<OrganizationSponsorship>());
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.Received(1)
|
||||
.UpsertManyAsync(Arg.Is<IEnumerable<OrganizationSponsorship>>(sponsorships => sponsorships.Count() == 2));
|
||||
|
||||
var (syncData, toEmailSponsorships) = await sutProvider.Sut.SyncOrganization(sponsoringOrganization, new[]
|
||||
{
|
||||
new OrganizationSponsorshipData(badOrganizationSponsorship),
|
||||
});
|
||||
// Deletes the sponsorship that had delete requested and is not sponsoring an org
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.Received(1)
|
||||
.DeleteManyAsync(Arg.Is<IEnumerable<Guid>>(toDeleteIds =>
|
||||
toDeleteIds.Count() == 1 && toDeleteIds.ElementAt(0) == canDeleteSponsorship.Id));
|
||||
}
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_BadData_DoesNotSave(SutProvider<CloudSyncSponsorshipsCommand> sutProvider,
|
||||
Organization sponsoringOrganization, OrganizationSponsorship badOrganizationSponsorship)
|
||||
{
|
||||
sponsoringOrganization.PlanType = PlanType.EnterpriseAnnually;
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
}
|
||||
badOrganizationSponsorship.ToDelete = true;
|
||||
badOrganizationSponsorship.LastSyncDate = null;
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_OrgDisabledForFourMonths_DoesNotSave(SutProvider<CloudSyncSponsorshipsCommand> sutProvider,
|
||||
Organization sponsoringOrganization, OrganizationSponsorship organizationSponsorship)
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetManyBySponsoringOrganizationAsync(sponsoringOrganization.Id)
|
||||
.Returns(new List<OrganizationSponsorship>());
|
||||
|
||||
var (syncData, toEmailSponsorships) = await sutProvider.Sut.SyncOrganization(sponsoringOrganization, new[]
|
||||
{
|
||||
sponsoringOrganization.PlanType = PlanType.EnterpriseAnnually;
|
||||
sponsoringOrganization.Enabled = false;
|
||||
sponsoringOrganization.ExpirationDate = DateTime.UtcNow.AddDays(-120);
|
||||
new OrganizationSponsorshipData(badOrganizationSponsorship),
|
||||
});
|
||||
|
||||
organizationSponsorship.ToDelete = false;
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetManyBySponsoringOrganizationAsync(sponsoringOrganization.Id)
|
||||
.Returns(new List<OrganizationSponsorship>());
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
}
|
||||
|
||||
var (syncData, toEmailSponsorships) = await sutProvider.Sut.SyncOrganization(sponsoringOrganization, new[]
|
||||
{
|
||||
new OrganizationSponsorshipData(organizationSponsorship),
|
||||
});
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_OrgDisabledForFourMonths_DoesNotSave(SutProvider<CloudSyncSponsorshipsCommand> sutProvider,
|
||||
Organization sponsoringOrganization, OrganizationSponsorship organizationSponsorship)
|
||||
{
|
||||
sponsoringOrganization.PlanType = PlanType.EnterpriseAnnually;
|
||||
sponsoringOrganization.Enabled = false;
|
||||
sponsoringOrganization.ExpirationDate = DateTime.UtcNow.AddDays(-120);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
organizationSponsorship.ToDelete = false;
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
}
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetManyBySponsoringOrganizationAsync(sponsoringOrganization.Id)
|
||||
.Returns(new List<OrganizationSponsorship>());
|
||||
|
||||
var (syncData, toEmailSponsorships) = await sutProvider.Sut.SyncOrganization(sponsoringOrganization, new[]
|
||||
{
|
||||
new OrganizationSponsorshipData(organizationSponsorship),
|
||||
});
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
}
|
||||
}
|
||||
|
@ -6,22 +6,21 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationSponsorshipRenewCommandTests
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationSponsorshipRenewCommandTests
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateExpirationDate_UpdatesValidUntil(OrganizationSponsorship sponsorship, DateTime expireDate,
|
||||
SutProvider<OrganizationSponsorshipRenewCommand> sutProvider)
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task UpdateExpirationDate_UpdatesValidUntil(OrganizationSponsorship sponsorship, DateTime expireDate,
|
||||
SutProvider<OrganizationSponsorshipRenewCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>().GetBySponsoredOrganizationIdAsync(sponsorship.SponsoredOrganizationId.Value).Returns(sponsorship);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>().GetBySponsoredOrganizationIdAsync(sponsorship.SponsoredOrganizationId.Value).Returns(sponsorship);
|
||||
|
||||
await sutProvider.Sut.UpdateExpirationDateAsync(sponsorship.SponsoredOrganizationId.Value, expireDate);
|
||||
await sutProvider.Sut.UpdateExpirationDateAsync(sponsorship.SponsoredOrganizationId.Value, expireDate);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().Received(1)
|
||||
.UpsertAsync(sponsorship);
|
||||
}
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().Received(1)
|
||||
.UpsertAsync(sponsorship);
|
||||
}
|
||||
}
|
||||
|
@ -6,38 +6,37 @@ using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise;
|
||||
|
||||
[SutProviderCustomize]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
public class RemoveSponsorshipCommandTests : CancelSponsorshipCommandTestsBase
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
public class RemoveSponsorshipCommandTests : CancelSponsorshipCommandTestsBase
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RemoveSponsorship_SponsoredOrgNull_ThrowsBadRequest(OrganizationSponsorship sponsorship,
|
||||
SutProvider<RemoveSponsorshipCommand> sutProvider)
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RemoveSponsorship_SponsoredOrgNull_ThrowsBadRequest(OrganizationSponsorship sponsorship,
|
||||
SutProvider<RemoveSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsorship.SponsoredOrganizationId = null;
|
||||
sponsorship.SponsoredOrganizationId = null;
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RemoveSponsorshipAsync(sponsorship));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RemoveSponsorshipAsync(sponsorship));
|
||||
|
||||
Assert.Contains("The requested organization is not currently being sponsored.", exception.Message);
|
||||
Assert.False(sponsorship.ToDelete);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
await AssertDidNotUpdateSponsorshipAsync(sutProvider);
|
||||
}
|
||||
Assert.Contains("The requested organization is not currently being sponsored.", exception.Message);
|
||||
Assert.False(sponsorship.ToDelete);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
await AssertDidNotUpdateSponsorshipAsync(sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RemoveSponsorship_SponsorshipNotFound_ThrowsBadRequest(SutProvider<RemoveSponsorshipCommand> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RemoveSponsorshipAsync(null));
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RemoveSponsorship_SponsorshipNotFound_ThrowsBadRequest(SutProvider<RemoveSponsorshipCommand> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RemoveSponsorshipAsync(null));
|
||||
|
||||
Assert.Contains("The requested organization is not currently being sponsored.", exception.Message);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
await AssertDidNotUpdateSponsorshipAsync(sutProvider);
|
||||
}
|
||||
Assert.Contains("The requested organization is not currently being sponsored.", exception.Message);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
await AssertDidNotUpdateSponsorshipAsync(sutProvider);
|
||||
}
|
||||
}
|
||||
|
@ -10,115 +10,114 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise;
|
||||
|
||||
[SutProviderCustomize]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
public class SendSponsorshipOfferCommandTests : FamiliesForEnterpriseTestsBase
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
public class SendSponsorshipOfferCommandTests : FamiliesForEnterpriseTestsBase
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SendSponsorshipOffer_SendSponsorshipOfferAsync_ExistingAccount_Success(OrganizationSponsorship sponsorship, string sponsoringOrgName, User user, SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SendSponsorshipOffer_SendSponsorshipOfferAsync_ExistingAccount_Success(OrganizationSponsorship sponsorship, string sponsoringOrgName, User user, SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IUserRepository>().GetByEmailAsync(sponsorship.OfferedToEmail).Returns(user);
|
||||
sutProvider.GetDependency<IUserRepository>().GetByEmailAsync(sponsorship.OfferedToEmail).Returns(user);
|
||||
|
||||
await sutProvider.Sut.SendSponsorshipOfferAsync(sponsorship, sponsoringOrgName);
|
||||
await sutProvider.Sut.SendSponsorshipOfferAsync(sponsorship, sponsoringOrgName);
|
||||
|
||||
await sutProvider.GetDependency<IMailService>().Received(1).SendFamiliesForEnterpriseOfferEmailAsync(sponsoringOrgName, sponsorship.OfferedToEmail, true, Arg.Any<string>());
|
||||
}
|
||||
await sutProvider.GetDependency<IMailService>().Received(1).SendFamiliesForEnterpriseOfferEmailAsync(sponsoringOrgName, sponsorship.OfferedToEmail, true, Arg.Any<string>());
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SendSponsorshipOffer_SendSponsorshipOfferAsync_NewAccount_Success(OrganizationSponsorship sponsorship, string sponsoringOrgName, SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IUserRepository>().GetByEmailAsync(sponsorship.OfferedToEmail).Returns((User)null);
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SendSponsorshipOffer_SendSponsorshipOfferAsync_NewAccount_Success(OrganizationSponsorship sponsorship, string sponsoringOrgName, SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IUserRepository>().GetByEmailAsync(sponsorship.OfferedToEmail).Returns((User)null);
|
||||
|
||||
await sutProvider.Sut.SendSponsorshipOfferAsync(sponsorship, sponsoringOrgName);
|
||||
await sutProvider.Sut.SendSponsorshipOfferAsync(sponsorship, sponsoringOrgName);
|
||||
|
||||
await sutProvider.GetDependency<IMailService>().Received(1).SendFamiliesForEnterpriseOfferEmailAsync(sponsoringOrgName, sponsorship.OfferedToEmail, false, Arg.Any<string>());
|
||||
}
|
||||
await sutProvider.GetDependency<IMailService>().Received(1).SendFamiliesForEnterpriseOfferEmailAsync(sponsoringOrgName, sponsorship.OfferedToEmail, false, Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ResendSponsorshipOffer_SponsoringOrgNotFound_ThrowsBadRequest(
|
||||
OrganizationUser orgUser, OrganizationSponsorship sponsorship,
|
||||
SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SendSponsorshipOfferAsync(null, orgUser, sponsorship));
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ResendSponsorshipOffer_SponsoringOrgNotFound_ThrowsBadRequest(
|
||||
OrganizationUser orgUser, OrganizationSponsorship sponsorship,
|
||||
SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SendSponsorshipOfferAsync(null, orgUser, sponsorship));
|
||||
|
||||
Assert.Contains("Cannot find the requested sponsoring organization.", exception.Message);
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SendFamiliesForEnterpriseOfferEmailAsync(default, default, default, default);
|
||||
}
|
||||
Assert.Contains("Cannot find the requested sponsoring organization.", exception.Message);
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SendFamiliesForEnterpriseOfferEmailAsync(default, default, default, default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ResendSponsorshipOffer_SponsoringOrgUserNotFound_ThrowsBadRequest(Organization org,
|
||||
OrganizationSponsorship sponsorship, SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SendSponsorshipOfferAsync(org, null, sponsorship));
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ResendSponsorshipOffer_SponsoringOrgUserNotFound_ThrowsBadRequest(Organization org,
|
||||
OrganizationSponsorship sponsorship, SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SendSponsorshipOfferAsync(org, null, sponsorship));
|
||||
|
||||
Assert.Contains("Only confirmed users can sponsor other organizations.", exception.Message);
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SendFamiliesForEnterpriseOfferEmailAsync(default, default, default, default);
|
||||
}
|
||||
Assert.Contains("Only confirmed users can sponsor other organizations.", exception.Message);
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SendFamiliesForEnterpriseOfferEmailAsync(default, default, default, default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
[BitMemberAutoData(nameof(NonConfirmedOrganizationUsersStatuses))]
|
||||
public async Task ResendSponsorshipOffer_SponsoringOrgUserNotConfirmed_ThrowsBadRequest(OrganizationUserStatusType status,
|
||||
Organization org, OrganizationUser orgUser, OrganizationSponsorship sponsorship,
|
||||
SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
orgUser.Status = status;
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
[BitMemberAutoData(nameof(NonConfirmedOrganizationUsersStatuses))]
|
||||
public async Task ResendSponsorshipOffer_SponsoringOrgUserNotConfirmed_ThrowsBadRequest(OrganizationUserStatusType status,
|
||||
Organization org, OrganizationUser orgUser, OrganizationSponsorship sponsorship,
|
||||
SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
orgUser.Status = status;
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SendSponsorshipOfferAsync(org, orgUser, sponsorship));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SendSponsorshipOfferAsync(org, orgUser, sponsorship));
|
||||
|
||||
Assert.Contains("Only confirmed users can sponsor other organizations.", exception.Message);
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SendFamiliesForEnterpriseOfferEmailAsync(default, default, default, default);
|
||||
}
|
||||
Assert.Contains("Only confirmed users can sponsor other organizations.", exception.Message);
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SendFamiliesForEnterpriseOfferEmailAsync(default, default, default, default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ResendSponsorshipOffer_SponsorshipNotFound_ThrowsBadRequest(Organization org,
|
||||
OrganizationUser orgUser,
|
||||
SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
orgUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ResendSponsorshipOffer_SponsorshipNotFound_ThrowsBadRequest(Organization org,
|
||||
OrganizationUser orgUser,
|
||||
SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
orgUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SendSponsorshipOfferAsync(org, orgUser, null));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SendSponsorshipOfferAsync(org, orgUser, null));
|
||||
|
||||
Assert.Contains("Cannot find an outstanding sponsorship offer for this organization.", exception.Message);
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SendFamiliesForEnterpriseOfferEmailAsync(default, default, default, default);
|
||||
}
|
||||
Assert.Contains("Cannot find an outstanding sponsorship offer for this organization.", exception.Message);
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SendFamiliesForEnterpriseOfferEmailAsync(default, default, default, default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ResendSponsorshipOffer_NoOfferToEmail_ThrowsBadRequest(Organization org,
|
||||
OrganizationUser orgUser, OrganizationSponsorship sponsorship,
|
||||
SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
orgUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
sponsorship.OfferedToEmail = null;
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ResendSponsorshipOffer_NoOfferToEmail_ThrowsBadRequest(Organization org,
|
||||
OrganizationUser orgUser, OrganizationSponsorship sponsorship,
|
||||
SutProvider<SendSponsorshipOfferCommand> sutProvider)
|
||||
{
|
||||
orgUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
sponsorship.OfferedToEmail = null;
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SendSponsorshipOfferAsync(org, orgUser, sponsorship));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SendSponsorshipOfferAsync(org, orgUser, sponsorship));
|
||||
|
||||
Assert.Contains("Cannot find an outstanding sponsorship offer for this organization.", exception.Message);
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SendFamiliesForEnterpriseOfferEmailAsync(default, default, default, default);
|
||||
}
|
||||
Assert.Contains("Cannot find an outstanding sponsorship offer for this organization.", exception.Message);
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SendFamiliesForEnterpriseOfferEmailAsync(default, default, default, default);
|
||||
}
|
||||
}
|
||||
|
@ -10,86 +10,85 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud;
|
||||
|
||||
[SutProviderCustomize]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
public class SetUpSponsorshipCommandTests : FamiliesForEnterpriseTestsBase
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
public class SetUpSponsorshipCommandTests : FamiliesForEnterpriseTestsBase
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SetUpSponsorship_SponsorshipNotFound_ThrowsBadRequest(Organization org,
|
||||
SutProvider<SetUpSponsorshipCommand> sutProvider)
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SetUpSponsorship_SponsorshipNotFound_ThrowsBadRequest(Organization org,
|
||||
SutProvider<SetUpSponsorshipCommand> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SetUpSponsorshipAsync(null, org));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SetUpSponsorshipAsync(null, org));
|
||||
|
||||
Assert.Contains("No unredeemed sponsorship offer exists for you.", exception.Message);
|
||||
await AssertDidNotSetUpAsync(sutProvider);
|
||||
}
|
||||
Assert.Contains("No unredeemed sponsorship offer exists for you.", exception.Message);
|
||||
await AssertDidNotSetUpAsync(sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SetUpSponsorship_OrgAlreadySponsored_ThrowsBadRequest(Organization org,
|
||||
OrganizationSponsorship sponsorship, OrganizationSponsorship existingSponsorship,
|
||||
SutProvider<SetUpSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(org.Id).Returns(existingSponsorship);
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SetUpSponsorship_OrgAlreadySponsored_ThrowsBadRequest(Organization org,
|
||||
OrganizationSponsorship sponsorship, OrganizationSponsorship existingSponsorship,
|
||||
SutProvider<SetUpSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(org.Id).Returns(existingSponsorship);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SetUpSponsorshipAsync(sponsorship, org));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SetUpSponsorshipAsync(sponsorship, org));
|
||||
|
||||
Assert.Contains("Cannot redeem a sponsorship offer for an organization that is already sponsored. Revoke existing sponsorship first.", exception.Message);
|
||||
await AssertDidNotSetUpAsync(sutProvider);
|
||||
}
|
||||
Assert.Contains("Cannot redeem a sponsorship offer for an organization that is already sponsored. Revoke existing sponsorship first.", exception.Message);
|
||||
await AssertDidNotSetUpAsync(sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(FamiliesPlanTypes))]
|
||||
public async Task SetUpSponsorship_TooLongSinceLastSync_ThrowsBadRequest(PlanType planType, Organization org,
|
||||
OrganizationSponsorship sponsorship,
|
||||
SutProvider<SetUpSponsorshipCommand> sutProvider)
|
||||
{
|
||||
org.PlanType = planType;
|
||||
sponsorship.LastSyncDate = DateTime.UtcNow.AddDays(-365);
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(FamiliesPlanTypes))]
|
||||
public async Task SetUpSponsorship_TooLongSinceLastSync_ThrowsBadRequest(PlanType planType, Organization org,
|
||||
OrganizationSponsorship sponsorship,
|
||||
SutProvider<SetUpSponsorshipCommand> sutProvider)
|
||||
{
|
||||
org.PlanType = planType;
|
||||
sponsorship.LastSyncDate = DateTime.UtcNow.AddDays(-365);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SetUpSponsorshipAsync(sponsorship, org));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SetUpSponsorshipAsync(sponsorship, org));
|
||||
|
||||
Assert.Contains("This sponsorship offer is more than 6 months old and has expired.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.Received(1)
|
||||
.DeleteAsync(sponsorship);
|
||||
await AssertDidNotSetUpAsync(sutProvider);
|
||||
}
|
||||
Assert.Contains("This sponsorship offer is more than 6 months old and has expired.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.Received(1)
|
||||
.DeleteAsync(sponsorship);
|
||||
await AssertDidNotSetUpAsync(sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(NonFamiliesPlanTypes))]
|
||||
public async Task SetUpSponsorship_OrgNotFamiles_ThrowsBadRequest(PlanType planType,
|
||||
OrganizationSponsorship sponsorship, Organization org,
|
||||
SutProvider<SetUpSponsorshipCommand> sutProvider)
|
||||
{
|
||||
org.PlanType = planType;
|
||||
sponsorship.LastSyncDate = DateTime.UtcNow;
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(NonFamiliesPlanTypes))]
|
||||
public async Task SetUpSponsorship_OrgNotFamiles_ThrowsBadRequest(PlanType planType,
|
||||
OrganizationSponsorship sponsorship, Organization org,
|
||||
SutProvider<SetUpSponsorshipCommand> sutProvider)
|
||||
{
|
||||
org.PlanType = planType;
|
||||
sponsorship.LastSyncDate = DateTime.UtcNow;
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SetUpSponsorshipAsync(sponsorship, org));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SetUpSponsorshipAsync(sponsorship, org));
|
||||
|
||||
Assert.Contains("Can only redeem sponsorship offer on families organizations.", exception.Message);
|
||||
await AssertDidNotSetUpAsync(sutProvider);
|
||||
}
|
||||
Assert.Contains("Can only redeem sponsorship offer on families organizations.", exception.Message);
|
||||
await AssertDidNotSetUpAsync(sutProvider);
|
||||
}
|
||||
|
||||
private static async Task AssertDidNotSetUpAsync(SutProvider<SetUpSponsorshipCommand> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IPaymentService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SponsorOrganizationAsync(default, default);
|
||||
await sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
private static async Task AssertDidNotSetUpAsync(SutProvider<SetUpSponsorshipCommand> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<IPaymentService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SponsorOrganizationAsync(default, default);
|
||||
await sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
}
|
||||
|
@ -8,51 +8,50 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class ValidateBillingSyncKeyCommandTests
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
public class ValidateBillingSyncKeyCommandTests
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateBillingSyncKeyAsync_NullOrganization_Throws(SutProvider<ValidateBillingSyncKeyCommand> sutProvider)
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateBillingSyncKeyAsync_NullOrganization_Throws(SutProvider<ValidateBillingSyncKeyCommand> sutProvider)
|
||||
{
|
||||
await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.ValidateBillingSyncKeyAsync(null, null));
|
||||
}
|
||||
await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.ValidateBillingSyncKeyAsync(null, null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData((string)null)]
|
||||
[BitAutoData("")]
|
||||
[BitAutoData(" ")]
|
||||
public async Task ValidateBillingSyncKeyAsync_BadString_ReturnsFalse(string billingSyncKey, SutProvider<ValidateBillingSyncKeyCommand> sutProvider)
|
||||
{
|
||||
Assert.False(await sutProvider.Sut.ValidateBillingSyncKeyAsync(new Organization(), billingSyncKey));
|
||||
}
|
||||
[Theory]
|
||||
[BitAutoData((string)null)]
|
||||
[BitAutoData("")]
|
||||
[BitAutoData(" ")]
|
||||
public async Task ValidateBillingSyncKeyAsync_BadString_ReturnsFalse(string billingSyncKey, SutProvider<ValidateBillingSyncKeyCommand> sutProvider)
|
||||
{
|
||||
Assert.False(await sutProvider.Sut.ValidateBillingSyncKeyAsync(new Organization(), billingSyncKey));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateBillingSyncKeyAsync_KeyEquals_ReturnsTrue(SutProvider<ValidateBillingSyncKeyCommand> sutProvider,
|
||||
Organization organization, OrganizationApiKey orgApiKey, string billingSyncKey)
|
||||
{
|
||||
orgApiKey.ApiKey = billingSyncKey;
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateBillingSyncKeyAsync_KeyEquals_ReturnsTrue(SutProvider<ValidateBillingSyncKeyCommand> sutProvider,
|
||||
Organization organization, OrganizationApiKey orgApiKey, string billingSyncKey)
|
||||
{
|
||||
orgApiKey.ApiKey = billingSyncKey;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationApiKeyRepository>()
|
||||
.GetManyByOrganizationIdTypeAsync(organization.Id, OrganizationApiKeyType.BillingSync)
|
||||
.Returns(new[] { orgApiKey });
|
||||
sutProvider.GetDependency<IOrganizationApiKeyRepository>()
|
||||
.GetManyByOrganizationIdTypeAsync(organization.Id, OrganizationApiKeyType.BillingSync)
|
||||
.Returns(new[] { orgApiKey });
|
||||
|
||||
Assert.True(await sutProvider.Sut.ValidateBillingSyncKeyAsync(organization, billingSyncKey));
|
||||
}
|
||||
Assert.True(await sutProvider.Sut.ValidateBillingSyncKeyAsync(organization, billingSyncKey));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateBillingSyncKeyAsync_KeyDoesNotEqual_ReturnsFalse(SutProvider<ValidateBillingSyncKeyCommand> sutProvider,
|
||||
Organization organization, OrganizationApiKey orgApiKey, string billingSyncKey)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationApiKeyRepository>()
|
||||
.GetManyByOrganizationIdTypeAsync(organization.Id, OrganizationApiKeyType.BillingSync)
|
||||
.Returns(new[] { orgApiKey });
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateBillingSyncKeyAsync_KeyDoesNotEqual_ReturnsFalse(SutProvider<ValidateBillingSyncKeyCommand> sutProvider,
|
||||
Organization organization, OrganizationApiKey orgApiKey, string billingSyncKey)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationApiKeyRepository>()
|
||||
.GetManyByOrganizationIdTypeAsync(organization.Id, OrganizationApiKeyType.BillingSync)
|
||||
.Returns(new[] { orgApiKey });
|
||||
|
||||
Assert.False(await sutProvider.Sut.ValidateBillingSyncKeyAsync(organization, billingSyncKey));
|
||||
}
|
||||
Assert.False(await sutProvider.Sut.ValidateBillingSyncKeyAsync(organization, billingSyncKey));
|
||||
}
|
||||
}
|
||||
|
@ -9,79 +9,78 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class ValidateRedemptionTokenCommandTests
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
public class ValidateRedemptionTokenCommandTests
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateRedemptionTokenAsync_CannotUnprotect_ReturnsFalse(SutProvider<ValidateRedemptionTokenCommand> sutProvider,
|
||||
string encryptedString)
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateRedemptionTokenAsync_CannotUnprotect_ReturnsFalse(SutProvider<ValidateRedemptionTokenCommand> sutProvider,
|
||||
string encryptedString)
|
||||
{
|
||||
sutProvider
|
||||
.GetDependency<IDataProtectorTokenFactory<OrganizationSponsorshipOfferTokenable>>()
|
||||
.TryUnprotect(encryptedString, out _)
|
||||
.Returns(call =>
|
||||
{
|
||||
call[1] = null;
|
||||
return false;
|
||||
});
|
||||
sutProvider
|
||||
.GetDependency<IDataProtectorTokenFactory<OrganizationSponsorshipOfferTokenable>>()
|
||||
.TryUnprotect(encryptedString, out _)
|
||||
.Returns(call =>
|
||||
{
|
||||
call[1] = null;
|
||||
return false;
|
||||
});
|
||||
|
||||
var (valid, sponsorship) = await sutProvider.Sut.ValidateRedemptionTokenAsync(encryptedString, null);
|
||||
Assert.False(valid);
|
||||
Assert.Null(sponsorship);
|
||||
}
|
||||
var (valid, sponsorship) = await sutProvider.Sut.ValidateRedemptionTokenAsync(encryptedString, null);
|
||||
Assert.False(valid);
|
||||
Assert.Null(sponsorship);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateRedemptionTokenAsync_NoSponsorship_ReturnsFalse(SutProvider<ValidateRedemptionTokenCommand> sutProvider,
|
||||
string encryptedString, OrganizationSponsorshipOfferTokenable tokenable)
|
||||
{
|
||||
sutProvider
|
||||
.GetDependency<IDataProtectorTokenFactory<OrganizationSponsorshipOfferTokenable>>()
|
||||
.TryUnprotect(encryptedString, out _)
|
||||
.Returns(call =>
|
||||
{
|
||||
call[1] = tokenable;
|
||||
return true;
|
||||
});
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateRedemptionTokenAsync_NoSponsorship_ReturnsFalse(SutProvider<ValidateRedemptionTokenCommand> sutProvider,
|
||||
string encryptedString, OrganizationSponsorshipOfferTokenable tokenable)
|
||||
{
|
||||
sutProvider
|
||||
.GetDependency<IDataProtectorTokenFactory<OrganizationSponsorshipOfferTokenable>>()
|
||||
.TryUnprotect(encryptedString, out _)
|
||||
.Returns(call =>
|
||||
{
|
||||
call[1] = tokenable;
|
||||
return true;
|
||||
});
|
||||
|
||||
var (valid, sponsorship) = await sutProvider.Sut.ValidateRedemptionTokenAsync(encryptedString, "test@email.com");
|
||||
Assert.False(valid);
|
||||
Assert.Null(sponsorship);
|
||||
}
|
||||
var (valid, sponsorship) = await sutProvider.Sut.ValidateRedemptionTokenAsync(encryptedString, "test@email.com");
|
||||
Assert.False(valid);
|
||||
Assert.Null(sponsorship);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateRedemptionTokenAsync_ValidSponsorship_ReturnsFalse(SutProvider<ValidateRedemptionTokenCommand> sutProvider,
|
||||
string encryptedString, string email, OrganizationSponsorshipOfferTokenable tokenable)
|
||||
{
|
||||
tokenable.Email = email;
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateRedemptionTokenAsync_ValidSponsorship_ReturnsFalse(SutProvider<ValidateRedemptionTokenCommand> sutProvider,
|
||||
string encryptedString, string email, OrganizationSponsorshipOfferTokenable tokenable)
|
||||
{
|
||||
tokenable.Email = email;
|
||||
|
||||
sutProvider
|
||||
.GetDependency<IDataProtectorTokenFactory<OrganizationSponsorshipOfferTokenable>>()
|
||||
.TryUnprotect(encryptedString, out _)
|
||||
.Returns(call =>
|
||||
{
|
||||
call[1] = tokenable;
|
||||
return true;
|
||||
});
|
||||
sutProvider
|
||||
.GetDependency<IDataProtectorTokenFactory<OrganizationSponsorshipOfferTokenable>>()
|
||||
.TryUnprotect(encryptedString, out _)
|
||||
.Returns(call =>
|
||||
{
|
||||
call[1] = tokenable;
|
||||
return true;
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetByIdAsync(tokenable.Id)
|
||||
.Returns(new OrganizationSponsorship
|
||||
{
|
||||
Id = tokenable.Id,
|
||||
PlanSponsorshipType = PlanSponsorshipType.FamiliesForEnterprise,
|
||||
OfferedToEmail = email
|
||||
});
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetByIdAsync(tokenable.Id)
|
||||
.Returns(new OrganizationSponsorship
|
||||
{
|
||||
Id = tokenable.Id,
|
||||
PlanSponsorshipType = PlanSponsorshipType.FamiliesForEnterprise,
|
||||
OfferedToEmail = email
|
||||
});
|
||||
|
||||
var (valid, sponsorship) = await sutProvider.Sut
|
||||
.ValidateRedemptionTokenAsync(encryptedString, email);
|
||||
var (valid, sponsorship) = await sutProvider.Sut
|
||||
.ValidateRedemptionTokenAsync(encryptedString, email);
|
||||
|
||||
Assert.True(valid);
|
||||
Assert.NotNull(sponsorship);
|
||||
}
|
||||
Assert.True(valid);
|
||||
Assert.NotNull(sponsorship);
|
||||
}
|
||||
}
|
||||
|
@ -8,247 +8,246 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud;
|
||||
|
||||
[SutProviderCustomize]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
public class ValidateSponsorshipCommandTests : CancelSponsorshipCommandTestsBase
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
public class ValidateSponsorshipCommandTests : CancelSponsorshipCommandTestsBase
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateSponsorshipAsync_NoSponsoredOrg_EarlyReturn(Guid sponsoredOrgId,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateSponsorshipAsync_NoSponsoredOrg_EarlyReturn(Guid sponsoredOrgId,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrgId).Returns((Organization)null);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrgId).Returns((Organization)null);
|
||||
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrgId);
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrgId);
|
||||
|
||||
Assert.False(result);
|
||||
await AssertDidNotRemoveSponsoredPaymentAsync(sutProvider);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
}
|
||||
Assert.False(result);
|
||||
await AssertDidNotRemoveSponsoredPaymentAsync(sutProvider);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateSponsorshipAsync_NoExistingSponsorship_UpdatesStripePlan(Organization sponsoredOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateSponsorshipAsync_NoExistingSponsorship_UpdatesStripePlan(Organization sponsoredOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, null, sutProvider);
|
||||
}
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, null, sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgDefault_UpdatesStripePlan(Organization sponsoredOrg,
|
||||
OrganizationSponsorship existingSponsorship, SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
existingSponsorship.SponsoringOrganizationId = default;
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgDefault_UpdatesStripePlan(Organization sponsoredOrg,
|
||||
OrganizationSponsorship existingSponsorship, SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
existingSponsorship.SponsoringOrganizationId = default;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgUserDefault_UpdatesStripePlan(Organization sponsoredOrg,
|
||||
OrganizationSponsorship existingSponsorship, SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
existingSponsorship.SponsoringOrganizationUserId = default;
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgUserDefault_UpdatesStripePlan(Organization sponsoredOrg,
|
||||
OrganizationSponsorship existingSponsorship, SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
existingSponsorship.SponsoringOrganizationUserId = default;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateSponsorshipAsync_SponsorshipTypeNull_UpdatesStripePlan(Organization sponsoredOrg,
|
||||
OrganizationSponsorship existingSponsorship, SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
existingSponsorship.PlanSponsorshipType = null;
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateSponsorshipAsync_SponsorshipTypeNull_UpdatesStripePlan(Organization sponsoredOrg,
|
||||
OrganizationSponsorship existingSponsorship, SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
existingSponsorship.PlanSponsorshipType = null;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgNotFound_UpdatesStripePlan(Organization sponsoredOrg,
|
||||
OrganizationSponsorship existingSponsorship, SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgNotFound_UpdatesStripePlan(Organization sponsoredOrg,
|
||||
OrganizationSponsorship existingSponsorship, SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(NonEnterprisePlanTypes))]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgNotEnterprise_UpdatesStripePlan(PlanType planType,
|
||||
Organization sponsoredOrg, OrganizationSponsorship existingSponsorship, Organization sponsoringOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = planType;
|
||||
existingSponsorship.SponsoringOrganizationId = sponsoringOrg.Id;
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(NonEnterprisePlanTypes))]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgNotEnterprise_UpdatesStripePlan(PlanType planType,
|
||||
Organization sponsoredOrg, OrganizationSponsorship existingSponsorship, Organization sponsoringOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = planType;
|
||||
existingSponsorship.SponsoringOrganizationId = sponsoringOrg.Id;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoringOrg.Id).Returns(sponsoringOrg);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoringOrg.Id).Returns(sponsoringOrg);
|
||||
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(EnterprisePlanTypes))]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgDisabledLongerThanGrace_UpdatesStripePlan(PlanType planType,
|
||||
Organization sponsoredOrg, OrganizationSponsorship existingSponsorship, Organization sponsoringOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = planType;
|
||||
sponsoringOrg.Enabled = false;
|
||||
sponsoringOrg.ExpirationDate = DateTime.UtcNow.AddDays(-100);
|
||||
existingSponsorship.SponsoringOrganizationId = sponsoringOrg.Id;
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(EnterprisePlanTypes))]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgDisabledLongerThanGrace_UpdatesStripePlan(PlanType planType,
|
||||
Organization sponsoredOrg, OrganizationSponsorship existingSponsorship, Organization sponsoringOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = planType;
|
||||
sponsoringOrg.Enabled = false;
|
||||
sponsoringOrg.ExpirationDate = DateTime.UtcNow.AddDays(-100);
|
||||
existingSponsorship.SponsoringOrganizationId = sponsoringOrg.Id;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoringOrg.Id).Returns(sponsoringOrg);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoringOrg.Id).Returns(sponsoringOrg);
|
||||
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OrganizationSponsorshipCustomize(ToDelete = true)]
|
||||
[BitMemberAutoData(nameof(EnterprisePlanTypes))]
|
||||
public async Task ValidateSponsorshipAsync_ToDeleteSponsorship_IsInvalid(PlanType planType,
|
||||
Organization sponsoredOrg, OrganizationSponsorship sponsorship, Organization sponsoringOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = planType;
|
||||
sponsoringOrg.Enabled = true;
|
||||
sponsorship.SponsoringOrganizationId = sponsoringOrg.Id;
|
||||
[Theory]
|
||||
[OrganizationSponsorshipCustomize(ToDelete = true)]
|
||||
[BitMemberAutoData(nameof(EnterprisePlanTypes))]
|
||||
public async Task ValidateSponsorshipAsync_ToDeleteSponsorship_IsInvalid(PlanType planType,
|
||||
Organization sponsoredOrg, OrganizationSponsorship sponsorship, Organization sponsoringOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = planType;
|
||||
sponsoringOrg.Enabled = true;
|
||||
sponsorship.SponsoringOrganizationId = sponsoringOrg.Id;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(sponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoringOrg.Id).Returns(sponsoringOrg);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(sponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoringOrg.Id).Returns(sponsoringOrg);
|
||||
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
|
||||
Assert.False(result);
|
||||
Assert.False(result);
|
||||
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, sponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(sponsorship, sutProvider);
|
||||
}
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, sponsorship, sutProvider);
|
||||
await AssertDeletedSponsorshipAsync(sponsorship, sutProvider);
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(EnterprisePlanTypes))]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgDisabledUnknownTime_UpdatesStripePlan(PlanType planType,
|
||||
Organization sponsoredOrg, OrganizationSponsorship existingSponsorship, Organization sponsoringOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = planType;
|
||||
sponsoringOrg.Enabled = false;
|
||||
sponsoringOrg.ExpirationDate = null;
|
||||
existingSponsorship.SponsoringOrganizationId = sponsoringOrg.Id;
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(EnterprisePlanTypes))]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgDisabledUnknownTime_UpdatesStripePlan(PlanType planType,
|
||||
Organization sponsoredOrg, OrganizationSponsorship existingSponsorship, Organization sponsoringOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = planType;
|
||||
sponsoringOrg.Enabled = false;
|
||||
sponsoringOrg.ExpirationDate = null;
|
||||
existingSponsorship.SponsoringOrganizationId = sponsoringOrg.Id;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoringOrg.Id).Returns(sponsoringOrg);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoringOrg.Id).Returns(sponsoringOrg);
|
||||
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertRemovedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
Assert.False(result);
|
||||
await AssertRemovedSponsoredPaymentAsync(sponsoredOrg, existingSponsorship, sutProvider);
|
||||
await AssertRemovedSponsorshipAsync(existingSponsorship, sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(EnterprisePlanTypes))]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgDisabledLessThanGrace_Valid(PlanType planType,
|
||||
Organization sponsoredOrg, OrganizationSponsorship existingSponsorship, Organization sponsoringOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = planType;
|
||||
sponsoringOrg.Enabled = true;
|
||||
sponsoringOrg.ExpirationDate = DateTime.UtcNow.AddDays(-1);
|
||||
existingSponsorship.SponsoringOrganizationId = sponsoringOrg.Id;
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(EnterprisePlanTypes))]
|
||||
public async Task ValidateSponsorshipAsync_SponsoringOrgDisabledLessThanGrace_Valid(PlanType planType,
|
||||
Organization sponsoredOrg, OrganizationSponsorship existingSponsorship, Organization sponsoringOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = planType;
|
||||
sponsoringOrg.Enabled = true;
|
||||
sponsoringOrg.ExpirationDate = DateTime.UtcNow.AddDays(-1);
|
||||
existingSponsorship.SponsoringOrganizationId = sponsoringOrg.Id;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoringOrg.Id).Returns(sponsoringOrg);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoringOrg.Id).Returns(sponsoringOrg);
|
||||
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
|
||||
Assert.True(result);
|
||||
Assert.True(result);
|
||||
|
||||
await AssertDidNotRemoveSponsoredPaymentAsync(sutProvider);
|
||||
await AssertDidNotRemoveSponsorshipAsync(sutProvider);
|
||||
}
|
||||
await AssertDidNotRemoveSponsoredPaymentAsync(sutProvider);
|
||||
await AssertDidNotRemoveSponsorshipAsync(sutProvider);
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(EnterprisePlanTypes))]
|
||||
public async Task ValidateSponsorshipAsync_Valid(PlanType planType,
|
||||
Organization sponsoredOrg, OrganizationSponsorship existingSponsorship, Organization sponsoringOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = planType;
|
||||
sponsoringOrg.Enabled = true;
|
||||
existingSponsorship.SponsoringOrganizationId = sponsoringOrg.Id;
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(EnterprisePlanTypes))]
|
||||
public async Task ValidateSponsorshipAsync_Valid(PlanType planType,
|
||||
Organization sponsoredOrg, OrganizationSponsorship existingSponsorship, Organization sponsoringOrg,
|
||||
SutProvider<ValidateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = planType;
|
||||
sponsoringOrg.Enabled = true;
|
||||
existingSponsorship.SponsoringOrganizationId = sponsoringOrg.Id;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoringOrg.Id).Returns(sponsoringOrg);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoredOrganizationIdAsync(sponsoredOrg.Id).Returns(existingSponsorship);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoredOrg.Id).Returns(sponsoredOrg);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(sponsoringOrg.Id).Returns(sponsoringOrg);
|
||||
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
var result = await sutProvider.Sut.ValidateSponsorshipAsync(sponsoredOrg.Id);
|
||||
|
||||
Assert.True(result);
|
||||
Assert.True(result);
|
||||
|
||||
await AssertDidNotRemoveSponsoredPaymentAsync(sutProvider);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
}
|
||||
await AssertDidNotRemoveSponsoredPaymentAsync(sutProvider);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
}
|
||||
}
|
||||
|
@ -13,167 +13,166 @@ using NSubstitute.ExceptionExtensions;
|
||||
using NSubstitute.ReturnsExtensions;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class CreateSponsorshipCommandTests : FamiliesForEnterpriseTestsBase
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
public class CreateSponsorshipCommandTests : FamiliesForEnterpriseTestsBase
|
||||
private bool SponsorshipValidator(OrganizationSponsorship sponsorship, OrganizationSponsorship expectedSponsorship)
|
||||
{
|
||||
private bool SponsorshipValidator(OrganizationSponsorship sponsorship, OrganizationSponsorship expectedSponsorship)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
AssertHelper.AssertPropertyEqual(sponsorship, expectedSponsorship, nameof(OrganizationSponsorship.Id));
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
AssertHelper.AssertPropertyEqual(sponsorship, expectedSponsorship, nameof(OrganizationSponsorship.Id));
|
||||
return true;
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task CreateSponsorship_OfferedToNotFound_ThrowsBadRequest(OrganizationUser orgUser, SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
catch
|
||||
{
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(orgUser.UserId.Value).ReturnsNull();
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.CreateSponsorshipAsync(null, orgUser, PlanSponsorshipType.FamiliesForEnterprise, default, default));
|
||||
|
||||
Assert.Contains("Cannot offer a Families Organization Sponsorship to yourself. Choose a different email.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.CreateAsync(default);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task CreateSponsorship_OfferedToSelf_ThrowsBadRequest(OrganizationUser orgUser, string sponsoredEmail, User user, SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
user.Email = sponsoredEmail;
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(orgUser.UserId.Value).Returns(user);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.CreateSponsorshipAsync(null, orgUser, PlanSponsorshipType.FamiliesForEnterprise, sponsoredEmail, default));
|
||||
|
||||
Assert.Contains("Cannot offer a Families Organization Sponsorship to yourself. Choose a different email.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.CreateAsync(default);
|
||||
}
|
||||
|
||||
[Theory, BitMemberAutoData(nameof(NonEnterprisePlanTypes))]
|
||||
public async Task CreateSponsorship_BadSponsoringOrgPlan_ThrowsBadRequest(PlanType sponsoringOrgPlan,
|
||||
Organization org, OrganizationUser orgUser, User user, SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
org.PlanType = sponsoringOrgPlan;
|
||||
orgUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(orgUser.UserId.Value).Returns(user);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.CreateSponsorshipAsync(org, orgUser, PlanSponsorshipType.FamiliesForEnterprise, default, default));
|
||||
|
||||
Assert.Contains("Specified Organization cannot sponsor other organizations.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.CreateAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(NonConfirmedOrganizationUsersStatuses))]
|
||||
public async Task CreateSponsorship_BadSponsoringUserStatus_ThrowsBadRequest(
|
||||
OrganizationUserStatusType statusType, Organization org, OrganizationUser orgUser, User user,
|
||||
SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
org.PlanType = PlanType.EnterpriseAnnually;
|
||||
orgUser.Status = statusType;
|
||||
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(orgUser.UserId.Value).Returns(user);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.CreateSponsorshipAsync(org, orgUser, PlanSponsorshipType.FamiliesForEnterprise, default, default));
|
||||
|
||||
Assert.Contains("Only confirmed users can sponsor other organizations.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.CreateAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
[BitAutoData]
|
||||
public async Task CreateSponsorship_AlreadySponsoring_Throws(Organization org,
|
||||
OrganizationUser orgUser, User user, OrganizationSponsorship sponsorship,
|
||||
SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
org.PlanType = PlanType.EnterpriseAnnually;
|
||||
orgUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(orgUser.UserId.Value).Returns(user);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoringOrganizationUserIdAsync(orgUser.Id).Returns(sponsorship);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.CreateSponsorshipAsync(org, orgUser, sponsorship.PlanSponsorshipType.Value, default, default));
|
||||
|
||||
Assert.Contains("Can only sponsor one organization per Organization User.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.CreateAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CreateSponsorship_CreatesSponsorship(Organization sponsoringOrg, OrganizationUser sponsoringOrgUser, User user,
|
||||
string sponsoredEmail, string friendlyName, Guid sponsorshipId, SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = PlanType.EnterpriseAnnually;
|
||||
sponsoringOrgUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(sponsoringOrgUser.UserId.Value).Returns(user);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>().WhenForAnyArgs(x => x.UpsertAsync(default)).Do(callInfo =>
|
||||
{
|
||||
var sponsorship = callInfo.Arg<OrganizationSponsorship>();
|
||||
sponsorship.Id = sponsorshipId;
|
||||
});
|
||||
|
||||
|
||||
await sutProvider.Sut.CreateSponsorshipAsync(sponsoringOrg, sponsoringOrgUser,
|
||||
PlanSponsorshipType.FamiliesForEnterprise, sponsoredEmail, friendlyName);
|
||||
|
||||
var expectedSponsorship = new OrganizationSponsorship
|
||||
{
|
||||
Id = sponsorshipId,
|
||||
SponsoringOrganizationId = sponsoringOrg.Id,
|
||||
SponsoringOrganizationUserId = sponsoringOrgUser.Id,
|
||||
FriendlyName = friendlyName,
|
||||
OfferedToEmail = sponsoredEmail,
|
||||
PlanSponsorshipType = PlanSponsorshipType.FamiliesForEnterprise,
|
||||
};
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().Received(1)
|
||||
.UpsertAsync(Arg.Is<OrganizationSponsorship>(s => SponsorshipValidator(s, expectedSponsorship)));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CreateSponsorship_CreateSponsorshipThrows_RevertsDatabase(Organization sponsoringOrg, OrganizationUser sponsoringOrgUser, User user,
|
||||
string sponsoredEmail, string friendlyName, SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = PlanType.EnterpriseAnnually;
|
||||
sponsoringOrgUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
|
||||
var expectedException = new Exception();
|
||||
OrganizationSponsorship createdSponsorship = null;
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(sponsoringOrgUser.UserId.Value).Returns(user);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>().UpsertAsync(default).ThrowsForAnyArgs(callInfo =>
|
||||
{
|
||||
createdSponsorship = callInfo.ArgAt<OrganizationSponsorship>(0);
|
||||
createdSponsorship.Id = Guid.NewGuid();
|
||||
return expectedException;
|
||||
});
|
||||
|
||||
var actualException = await Assert.ThrowsAsync<Exception>(() =>
|
||||
sutProvider.Sut.CreateSponsorshipAsync(sponsoringOrg, sponsoringOrgUser,
|
||||
PlanSponsorshipType.FamiliesForEnterprise, sponsoredEmail, friendlyName));
|
||||
Assert.Same(expectedException, actualException);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().Received(1)
|
||||
.DeleteAsync(createdSponsorship);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task CreateSponsorship_OfferedToNotFound_ThrowsBadRequest(OrganizationUser orgUser, SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(orgUser.UserId.Value).ReturnsNull();
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.CreateSponsorshipAsync(null, orgUser, PlanSponsorshipType.FamiliesForEnterprise, default, default));
|
||||
|
||||
Assert.Contains("Cannot offer a Families Organization Sponsorship to yourself. Choose a different email.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.CreateAsync(default);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task CreateSponsorship_OfferedToSelf_ThrowsBadRequest(OrganizationUser orgUser, string sponsoredEmail, User user, SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
user.Email = sponsoredEmail;
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(orgUser.UserId.Value).Returns(user);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.CreateSponsorshipAsync(null, orgUser, PlanSponsorshipType.FamiliesForEnterprise, sponsoredEmail, default));
|
||||
|
||||
Assert.Contains("Cannot offer a Families Organization Sponsorship to yourself. Choose a different email.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.CreateAsync(default);
|
||||
}
|
||||
|
||||
[Theory, BitMemberAutoData(nameof(NonEnterprisePlanTypes))]
|
||||
public async Task CreateSponsorship_BadSponsoringOrgPlan_ThrowsBadRequest(PlanType sponsoringOrgPlan,
|
||||
Organization org, OrganizationUser orgUser, User user, SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
org.PlanType = sponsoringOrgPlan;
|
||||
orgUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(orgUser.UserId.Value).Returns(user);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.CreateSponsorshipAsync(org, orgUser, PlanSponsorshipType.FamiliesForEnterprise, default, default));
|
||||
|
||||
Assert.Contains("Specified Organization cannot sponsor other organizations.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.CreateAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(NonConfirmedOrganizationUsersStatuses))]
|
||||
public async Task CreateSponsorship_BadSponsoringUserStatus_ThrowsBadRequest(
|
||||
OrganizationUserStatusType statusType, Organization org, OrganizationUser orgUser, User user,
|
||||
SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
org.PlanType = PlanType.EnterpriseAnnually;
|
||||
orgUser.Status = statusType;
|
||||
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(orgUser.UserId.Value).Returns(user);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.CreateSponsorshipAsync(org, orgUser, PlanSponsorshipType.FamiliesForEnterprise, default, default));
|
||||
|
||||
Assert.Contains("Only confirmed users can sponsor other organizations.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.CreateAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
[BitAutoData]
|
||||
public async Task CreateSponsorship_AlreadySponsoring_Throws(Organization org,
|
||||
OrganizationUser orgUser, User user, OrganizationSponsorship sponsorship,
|
||||
SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
org.PlanType = PlanType.EnterpriseAnnually;
|
||||
orgUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(orgUser.UserId.Value).Returns(user);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetBySponsoringOrganizationUserIdAsync(orgUser.Id).Returns(sponsorship);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.CreateSponsorshipAsync(org, orgUser, sponsorship.PlanSponsorshipType.Value, default, default));
|
||||
|
||||
Assert.Contains("Can only sponsor one organization per Organization User.", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().DidNotReceiveWithAnyArgs()
|
||||
.CreateAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CreateSponsorship_CreatesSponsorship(Organization sponsoringOrg, OrganizationUser sponsoringOrgUser, User user,
|
||||
string sponsoredEmail, string friendlyName, Guid sponsorshipId, SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = PlanType.EnterpriseAnnually;
|
||||
sponsoringOrgUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(sponsoringOrgUser.UserId.Value).Returns(user);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>().WhenForAnyArgs(x => x.UpsertAsync(default)).Do(callInfo =>
|
||||
{
|
||||
var sponsorship = callInfo.Arg<OrganizationSponsorship>();
|
||||
sponsorship.Id = sponsorshipId;
|
||||
});
|
||||
|
||||
|
||||
await sutProvider.Sut.CreateSponsorshipAsync(sponsoringOrg, sponsoringOrgUser,
|
||||
PlanSponsorshipType.FamiliesForEnterprise, sponsoredEmail, friendlyName);
|
||||
|
||||
var expectedSponsorship = new OrganizationSponsorship
|
||||
{
|
||||
Id = sponsorshipId,
|
||||
SponsoringOrganizationId = sponsoringOrg.Id,
|
||||
SponsoringOrganizationUserId = sponsoringOrgUser.Id,
|
||||
FriendlyName = friendlyName,
|
||||
OfferedToEmail = sponsoredEmail,
|
||||
PlanSponsorshipType = PlanSponsorshipType.FamiliesForEnterprise,
|
||||
};
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().Received(1)
|
||||
.UpsertAsync(Arg.Is<OrganizationSponsorship>(s => SponsorshipValidator(s, expectedSponsorship)));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CreateSponsorship_CreateSponsorshipThrows_RevertsDatabase(Organization sponsoringOrg, OrganizationUser sponsoringOrgUser, User user,
|
||||
string sponsoredEmail, string friendlyName, SutProvider<CreateSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsoringOrg.PlanType = PlanType.EnterpriseAnnually;
|
||||
sponsoringOrgUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
|
||||
var expectedException = new Exception();
|
||||
OrganizationSponsorship createdSponsorship = null;
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(sponsoringOrgUser.UserId.Value).Returns(user);
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>().UpsertAsync(default).ThrowsForAnyArgs(callInfo =>
|
||||
{
|
||||
createdSponsorship = callInfo.ArgAt<OrganizationSponsorship>(0);
|
||||
createdSponsorship.Id = Guid.NewGuid();
|
||||
return expectedException;
|
||||
});
|
||||
|
||||
var actualException = await Assert.ThrowsAsync<Exception>(() =>
|
||||
sutProvider.Sut.CreateSponsorshipAsync(sponsoringOrg, sponsoringOrgUser,
|
||||
PlanSponsorshipType.FamiliesForEnterprise, sponsoredEmail, friendlyName));
|
||||
Assert.Same(expectedException, actualException);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>().Received(1)
|
||||
.DeleteAsync(createdSponsorship);
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,24 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise;
|
||||
|
||||
public abstract class FamiliesForEnterpriseTestsBase
|
||||
{
|
||||
public abstract class FamiliesForEnterpriseTestsBase
|
||||
{
|
||||
public static IEnumerable<object[]> EnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product == ProductType.Enterprise).Select(p => new object[] { p });
|
||||
public static IEnumerable<object[]> EnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product == ProductType.Enterprise).Select(p => new object[] { p });
|
||||
|
||||
public static IEnumerable<object[]> NonEnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product != ProductType.Enterprise).Select(p => new object[] { p });
|
||||
public static IEnumerable<object[]> NonEnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product != ProductType.Enterprise).Select(p => new object[] { p });
|
||||
|
||||
public static IEnumerable<object[]> FamiliesPlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product == ProductType.Families).Select(p => new object[] { p });
|
||||
public static IEnumerable<object[]> FamiliesPlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product == ProductType.Families).Select(p => new object[] { p });
|
||||
|
||||
public static IEnumerable<object[]> NonFamiliesPlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product != ProductType.Families).Select(p => new object[] { p });
|
||||
public static IEnumerable<object[]> NonFamiliesPlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).Product != ProductType.Families).Select(p => new object[] { p });
|
||||
|
||||
public static IEnumerable<object[]> NonConfirmedOrganizationUsersStatuses =>
|
||||
Enum.GetValues<OrganizationUserStatusType>()
|
||||
.Where(s => s != OrganizationUserStatusType.Confirmed)
|
||||
.Select(s => new object[] { s });
|
||||
}
|
||||
public static IEnumerable<object[]> NonConfirmedOrganizationUsersStatuses =>
|
||||
Enum.GetValues<OrganizationUserStatusType>()
|
||||
.Where(s => s != OrganizationUserStatusType.Confirmed)
|
||||
.Select(s => new object[] { s });
|
||||
}
|
||||
|
@ -6,48 +6,47 @@ using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.SelfHosted
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.SelfHosted;
|
||||
|
||||
[SutProviderCustomize]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
public class SelfHostedRevokeSponsorshipCommandTests : CancelSponsorshipCommandTestsBase
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
public class SelfHostedRevokeSponsorshipCommandTests : CancelSponsorshipCommandTestsBase
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_NoExistingSponsorship_ThrowsBadRequest(
|
||||
SutProvider<SelfHostedRevokeSponsorshipCommand> sutProvider)
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_NoExistingSponsorship_ThrowsBadRequest(
|
||||
SutProvider<SelfHostedRevokeSponsorshipCommand> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RevokeSponsorshipAsync(null));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.RevokeSponsorshipAsync(null));
|
||||
|
||||
Assert.Contains("You are not currently sponsoring an organization.", exception.Message);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
await AssertDidNotUpdateSponsorshipAsync(sutProvider);
|
||||
}
|
||||
Assert.Contains("You are not currently sponsoring an organization.", exception.Message);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
await AssertDidNotUpdateSponsorshipAsync(sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_SponsorshipNotSynced_DeletesSponsorship(OrganizationSponsorship sponsorship,
|
||||
SutProvider<SelfHostedRevokeSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsorship.LastSyncDate = null;
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_SponsorshipNotSynced_DeletesSponsorship(OrganizationSponsorship sponsorship,
|
||||
SutProvider<SelfHostedRevokeSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsorship.LastSyncDate = null;
|
||||
|
||||
await sutProvider.Sut.RevokeSponsorshipAsync(sponsorship);
|
||||
await AssertDeletedSponsorshipAsync(sponsorship, sutProvider);
|
||||
}
|
||||
await sutProvider.Sut.RevokeSponsorshipAsync(sponsorship);
|
||||
await AssertDeletedSponsorshipAsync(sponsorship, sutProvider);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_SponsorshipSynced_MarksForDeletion(OrganizationSponsorship sponsorship,
|
||||
SutProvider<SelfHostedRevokeSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsorship.LastSyncDate = DateTime.UtcNow;
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RevokeSponsorship_SponsorshipSynced_MarksForDeletion(OrganizationSponsorship sponsorship,
|
||||
SutProvider<SelfHostedRevokeSponsorshipCommand> sutProvider)
|
||||
{
|
||||
sponsorship.LastSyncDate = DateTime.UtcNow;
|
||||
|
||||
await sutProvider.Sut.RevokeSponsorshipAsync(sponsorship);
|
||||
await sutProvider.Sut.RevokeSponsorshipAsync(sponsorship);
|
||||
|
||||
Assert.True(sponsorship.ToDelete);
|
||||
await AssertUpdatedSponsorshipAsync(sponsorship, sutProvider);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
}
|
||||
Assert.True(sponsorship.ToDelete);
|
||||
await AssertUpdatedSponsorshipAsync(sponsorship, sutProvider);
|
||||
await AssertDidNotDeleteSponsorshipAsync(sutProvider);
|
||||
}
|
||||
}
|
||||
|
@ -15,174 +15,172 @@ using NSubstitute;
|
||||
using RichardSzalay.MockHttp;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.SelfHosted
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.SelfHosted;
|
||||
|
||||
public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTestsBase
|
||||
{
|
||||
|
||||
public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTestsBase
|
||||
public static SutProvider<SelfHostedSyncSponsorshipsCommand> GetSutProvider(bool enableCloudCommunication = true, string identityResponse = null, string apiResponse = null)
|
||||
{
|
||||
var fixture = new Fixture().WithAutoNSubstitutionsAutoPopulatedProperties();
|
||||
fixture.AddMockHttp();
|
||||
|
||||
public static SutProvider<SelfHostedSyncSponsorshipsCommand> GetSutProvider(bool enableCloudCommunication = true, string identityResponse = null, string apiResponse = null)
|
||||
var settings = fixture.Create<IGlobalSettings>();
|
||||
settings.SelfHosted = true;
|
||||
settings.EnableCloudCommunication = enableCloudCommunication;
|
||||
|
||||
var apiUri = fixture.Create<Uri>();
|
||||
var identityUri = fixture.Create<Uri>();
|
||||
settings.Installation.ApiUri.Returns(apiUri.ToString());
|
||||
settings.Installation.IdentityUri.Returns(identityUri.ToString());
|
||||
|
||||
var apiHandler = new MockHttpMessageHandler();
|
||||
var identityHandler = new MockHttpMessageHandler();
|
||||
var syncUri = string.Concat(apiUri, "organization/sponsorship/sync");
|
||||
var tokenUri = string.Concat(identityUri, "connect/token");
|
||||
|
||||
apiHandler.When(HttpMethod.Post, syncUri)
|
||||
.Respond("application/json", apiResponse);
|
||||
identityHandler.When(HttpMethod.Post, tokenUri)
|
||||
.Respond("application/json", identityResponse ?? "{\"access_token\":\"string\",\"expires_in\":3600,\"token_type\":\"Bearer\",\"scope\":\"string\"}");
|
||||
|
||||
|
||||
var apiHttp = apiHandler.ToHttpClient();
|
||||
var identityHttp = identityHandler.ToHttpClient();
|
||||
|
||||
var mockHttpClientFactory = Substitute.For<IHttpClientFactory>();
|
||||
mockHttpClientFactory.CreateClient(Arg.Is("client")).Returns(apiHttp);
|
||||
mockHttpClientFactory.CreateClient(Arg.Is("identity")).Returns(identityHttp);
|
||||
|
||||
return new SutProvider<SelfHostedSyncSponsorshipsCommand>(fixture)
|
||||
.SetDependency(settings)
|
||||
.SetDependency(mockHttpClientFactory)
|
||||
.Create();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_BillingSyncKeyDisabled_ThrowsBadRequest(
|
||||
Guid cloudOrganizationId, OrganizationConnection billingSyncConnection)
|
||||
{
|
||||
var sutProvider = GetSutProvider();
|
||||
billingSyncConnection.Enabled = false;
|
||||
billingSyncConnection.SetConfig(new BillingSyncConfig
|
||||
{
|
||||
var fixture = new Fixture().WithAutoNSubstitutionsAutoPopulatedProperties();
|
||||
fixture.AddMockHttp();
|
||||
BillingSyncKey = "okslkcslkjf"
|
||||
});
|
||||
|
||||
var settings = fixture.Create<IGlobalSettings>();
|
||||
settings.SelfHosted = true;
|
||||
settings.EnableCloudCommunication = enableCloudCommunication;
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection));
|
||||
|
||||
var apiUri = fixture.Create<Uri>();
|
||||
var identityUri = fixture.Create<Uri>();
|
||||
settings.Installation.ApiUri.Returns(apiUri.ToString());
|
||||
settings.Installation.IdentityUri.Returns(identityUri.ToString());
|
||||
Assert.Contains($"Billing Sync Key disabled", exception.Message);
|
||||
|
||||
var apiHandler = new MockHttpMessageHandler();
|
||||
var identityHandler = new MockHttpMessageHandler();
|
||||
var syncUri = string.Concat(apiUri, "organization/sponsorship/sync");
|
||||
var tokenUri = string.Concat(identityUri, "connect/token");
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
}
|
||||
|
||||
apiHandler.When(HttpMethod.Post, syncUri)
|
||||
.Respond("application/json", apiResponse);
|
||||
identityHandler.When(HttpMethod.Post, tokenUri)
|
||||
.Respond("application/json", identityResponse ?? "{\"access_token\":\"string\",\"expires_in\":3600,\"token_type\":\"Bearer\",\"scope\":\"string\"}");
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_BillingSyncKeyEmpty_ThrowsBadRequest(
|
||||
Guid cloudOrganizationId, OrganizationConnection billingSyncConnection)
|
||||
{
|
||||
var sutProvider = GetSutProvider();
|
||||
billingSyncConnection.Config = "";
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection));
|
||||
|
||||
var apiHttp = apiHandler.ToHttpClient();
|
||||
var identityHttp = identityHandler.ToHttpClient();
|
||||
Assert.Contains($"No Billing Sync Key known", exception.Message);
|
||||
|
||||
var mockHttpClientFactory = Substitute.For<IHttpClientFactory>();
|
||||
mockHttpClientFactory.CreateClient(Arg.Is("client")).Returns(apiHttp);
|
||||
mockHttpClientFactory.CreateClient(Arg.Is("identity")).Returns(identityHttp);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
}
|
||||
|
||||
return new SutProvider<SelfHostedSyncSponsorshipsCommand>(fixture)
|
||||
.SetDependency(settings)
|
||||
.SetDependency(mockHttpClientFactory)
|
||||
.Create();
|
||||
}
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_CloudCommunicationDisabled_EarlyReturn(
|
||||
Guid cloudOrganizationId, OrganizationConnection billingSyncConnection)
|
||||
{
|
||||
var sutProvider = GetSutProvider(false);
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_BillingSyncKeyDisabled_ThrowsBadRequest(
|
||||
Guid cloudOrganizationId, OrganizationConnection billingSyncConnection)
|
||||
{
|
||||
var sutProvider = GetSutProvider();
|
||||
billingSyncConnection.Enabled = false;
|
||||
billingSyncConnection.SetConfig(new BillingSyncConfig
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection));
|
||||
|
||||
Assert.Contains($"Cloud communication is disabled", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_SyncsSponsorships(
|
||||
Guid cloudOrganizationId, OrganizationConnection billingSyncConnection, IEnumerable<OrganizationSponsorship> sponsorships)
|
||||
{
|
||||
var syncJsonResponse = JsonSerializer.Serialize(new OrganizationSponsorshipSyncResponseModel(
|
||||
new OrganizationSponsorshipSyncData
|
||||
{
|
||||
BillingSyncKey = "okslkcslkjf"
|
||||
});
|
||||
SponsorshipsBatch = sponsorships.Select(o => new OrganizationSponsorshipData(o))
|
||||
}));
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection));
|
||||
|
||||
Assert.Contains($"Billing Sync Key disabled", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_BillingSyncKeyEmpty_ThrowsBadRequest(
|
||||
Guid cloudOrganizationId, OrganizationConnection billingSyncConnection)
|
||||
var sutProvider = GetSutProvider(apiResponse: syncJsonResponse);
|
||||
billingSyncConnection.SetConfig(new BillingSyncConfig
|
||||
{
|
||||
var sutProvider = GetSutProvider();
|
||||
billingSyncConnection.Config = "";
|
||||
BillingSyncKey = "okslkcslkjf"
|
||||
});
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetManyBySponsoringOrganizationAsync(Arg.Any<Guid>()).Returns(sponsorships.ToList());
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection));
|
||||
await sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection);
|
||||
|
||||
Assert.Contains($"No Billing Sync Key known", exception.Message);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.Received(1)
|
||||
.UpsertManyAsync(Arg.Any<IEnumerable<OrganizationSponsorship>>());
|
||||
}
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_CloudCommunicationDisabled_EarlyReturn(
|
||||
Guid cloudOrganizationId, OrganizationConnection billingSyncConnection)
|
||||
{
|
||||
var sutProvider = GetSutProvider(false);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection));
|
||||
|
||||
Assert.Contains($"Cloud communication is disabled", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OrganizationSponsorshipCustomize]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_SyncsSponsorships(
|
||||
Guid cloudOrganizationId, OrganizationConnection billingSyncConnection, IEnumerable<OrganizationSponsorship> sponsorships)
|
||||
{
|
||||
var syncJsonResponse = JsonSerializer.Serialize(new OrganizationSponsorshipSyncResponseModel(
|
||||
new OrganizationSponsorshipSyncData
|
||||
{
|
||||
SponsorshipsBatch = sponsorships.Select(o => new OrganizationSponsorshipData(o))
|
||||
}));
|
||||
|
||||
var sutProvider = GetSutProvider(apiResponse: syncJsonResponse);
|
||||
billingSyncConnection.SetConfig(new BillingSyncConfig
|
||||
[Theory]
|
||||
[OrganizationSponsorshipCustomize(ToDelete = true)]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_DeletesSponsorships(
|
||||
Guid cloudOrganizationId, OrganizationConnection billingSyncConnection, IEnumerable<OrganizationSponsorship> sponsorships)
|
||||
{
|
||||
var syncJsonResponse = JsonSerializer.Serialize(new OrganizationSponsorshipSyncResponseModel(
|
||||
new OrganizationSponsorshipSyncData
|
||||
{
|
||||
BillingSyncKey = "okslkcslkjf"
|
||||
});
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetManyBySponsoringOrganizationAsync(Arg.Any<Guid>()).Returns(sponsorships.ToList());
|
||||
SponsorshipsBatch = sponsorships.Select(o => new OrganizationSponsorshipData(o) { CloudSponsorshipRemoved = true })
|
||||
}));
|
||||
|
||||
await sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.DeleteManyAsync(default);
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.Received(1)
|
||||
.UpsertManyAsync(Arg.Any<IEnumerable<OrganizationSponsorship>>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OrganizationSponsorshipCustomize(ToDelete = true)]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_DeletesSponsorships(
|
||||
Guid cloudOrganizationId, OrganizationConnection billingSyncConnection, IEnumerable<OrganizationSponsorship> sponsorships)
|
||||
var sutProvider = GetSutProvider(apiResponse: syncJsonResponse);
|
||||
billingSyncConnection.SetConfig(new BillingSyncConfig
|
||||
{
|
||||
var syncJsonResponse = JsonSerializer.Serialize(new OrganizationSponsorshipSyncResponseModel(
|
||||
new OrganizationSponsorshipSyncData
|
||||
{
|
||||
SponsorshipsBatch = sponsorships.Select(o => new OrganizationSponsorshipData(o) { CloudSponsorshipRemoved = true })
|
||||
}));
|
||||
BillingSyncKey = "okslkcslkjf"
|
||||
});
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetManyBySponsoringOrganizationAsync(Arg.Any<Guid>()).Returns(sponsorships.ToList());
|
||||
|
||||
var sutProvider = GetSutProvider(apiResponse: syncJsonResponse);
|
||||
billingSyncConnection.SetConfig(new BillingSyncConfig
|
||||
{
|
||||
BillingSyncKey = "okslkcslkjf"
|
||||
});
|
||||
sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.GetManyBySponsoringOrganizationAsync(Arg.Any<Guid>()).Returns(sponsorships.ToList());
|
||||
await sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection);
|
||||
|
||||
await sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.Received(1)
|
||||
.DeleteManyAsync(Arg.Any<IEnumerable<Guid>>());
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
}
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.Received(1)
|
||||
.DeleteManyAsync(Arg.Any<IEnumerable<Guid>>());
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertManyAsync(default);
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,27 @@
|
||||
using Bit.Core.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Resources
|
||||
namespace Bit.Core.Test.Resources;
|
||||
|
||||
public class VerifyResources
|
||||
{
|
||||
public class VerifyResources
|
||||
[Theory]
|
||||
[MemberData(nameof(GetResources))]
|
||||
public void Resource_FoundAndReadable(string resourceName)
|
||||
{
|
||||
[Theory]
|
||||
[MemberData(nameof(GetResources))]
|
||||
public void Resource_FoundAndReadable(string resourceName)
|
||||
{
|
||||
var assembly = typeof(CoreHelpers).Assembly;
|
||||
var assembly = typeof(CoreHelpers).Assembly;
|
||||
|
||||
using (var resource = assembly.GetManifestResourceStream(resourceName))
|
||||
{
|
||||
Assert.NotNull(resource);
|
||||
Assert.True(resource.CanRead);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetResources()
|
||||
using (var resource = assembly.GetManifestResourceStream(resourceName))
|
||||
{
|
||||
yield return new[] { "Bit.Core.licensing.cer" };
|
||||
yield return new[] { "Bit.Core.MailTemplates.Handlebars.AddedCredit.html.hbs" };
|
||||
yield return new[] { "Bit.Core.MailTemplates.Handlebars.Layouts.Basic.html.hbs" };
|
||||
Assert.NotNull(resource);
|
||||
Assert.True(resource.CanRead);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetResources()
|
||||
{
|
||||
yield return new[] { "Bit.Core.licensing.cer" };
|
||||
yield return new[] { "Bit.Core.MailTemplates.Handlebars.AddedCredit.html.hbs" };
|
||||
yield return new[] { "Bit.Core.MailTemplates.Handlebars.Layouts.Basic.html.hbs" };
|
||||
}
|
||||
}
|
||||
|
@ -8,80 +8,79 @@ using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class AmazonSesMailDeliveryServiceTests : IDisposable
|
||||
{
|
||||
public class AmazonSesMailDeliveryServiceTests : IDisposable
|
||||
private readonly AmazonSesMailDeliveryService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IWebHostEnvironment _hostingEnvironment;
|
||||
private readonly ILogger<AmazonSesMailDeliveryService> _logger;
|
||||
private readonly IAmazonSimpleEmailService _amazonSimpleEmailService;
|
||||
|
||||
public AmazonSesMailDeliveryServiceTests()
|
||||
{
|
||||
private readonly AmazonSesMailDeliveryService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IWebHostEnvironment _hostingEnvironment;
|
||||
private readonly ILogger<AmazonSesMailDeliveryService> _logger;
|
||||
private readonly IAmazonSimpleEmailService _amazonSimpleEmailService;
|
||||
|
||||
public AmazonSesMailDeliveryServiceTests()
|
||||
_globalSettings = new GlobalSettings
|
||||
{
|
||||
_globalSettings = new GlobalSettings
|
||||
Amazon =
|
||||
{
|
||||
AccessKeyId = "AccessKeyId-AmazonSesMailDeliveryServiceTests",
|
||||
AccessKeySecret = "AccessKeySecret-AmazonSesMailDeliveryServiceTests",
|
||||
Region = "Region-AmazonSesMailDeliveryServiceTests"
|
||||
}
|
||||
};
|
||||
|
||||
_hostingEnvironment = Substitute.For<IWebHostEnvironment>();
|
||||
_logger = Substitute.For<ILogger<AmazonSesMailDeliveryService>>();
|
||||
_amazonSimpleEmailService = Substitute.For<IAmazonSimpleEmailService>();
|
||||
|
||||
_sut = new AmazonSesMailDeliveryService(
|
||||
_globalSettings,
|
||||
_hostingEnvironment,
|
||||
_logger,
|
||||
_amazonSimpleEmailService
|
||||
);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_sut?.Dispose();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendEmailAsync_CallsSendEmailAsync_WhenMessageIsValid()
|
||||
{
|
||||
var mailMessage = new MailMessage
|
||||
{
|
||||
ToEmails = new List<string> { "ToEmails" },
|
||||
BccEmails = new List<string> { "BccEmails" },
|
||||
Subject = "Subject",
|
||||
HtmlContent = "HtmlContent",
|
||||
TextContent = "TextContent",
|
||||
Category = "Category"
|
||||
};
|
||||
|
||||
await _sut.SendEmailAsync(mailMessage);
|
||||
|
||||
await _amazonSimpleEmailService.Received(1).SendEmailAsync(
|
||||
Arg.Do<SendEmailRequest>(request =>
|
||||
{
|
||||
Amazon =
|
||||
{
|
||||
AccessKeyId = "AccessKeyId-AmazonSesMailDeliveryServiceTests",
|
||||
AccessKeySecret = "AccessKeySecret-AmazonSesMailDeliveryServiceTests",
|
||||
Region = "Region-AmazonSesMailDeliveryServiceTests"
|
||||
}
|
||||
};
|
||||
Assert.False(string.IsNullOrEmpty(request.Source));
|
||||
|
||||
_hostingEnvironment = Substitute.For<IWebHostEnvironment>();
|
||||
_logger = Substitute.For<ILogger<AmazonSesMailDeliveryService>>();
|
||||
_amazonSimpleEmailService = Substitute.For<IAmazonSimpleEmailService>();
|
||||
Assert.Single(request.Destination.ToAddresses);
|
||||
Assert.Equal(mailMessage.ToEmails.First(), request.Destination.ToAddresses.First());
|
||||
|
||||
_sut = new AmazonSesMailDeliveryService(
|
||||
_globalSettings,
|
||||
_hostingEnvironment,
|
||||
_logger,
|
||||
_amazonSimpleEmailService
|
||||
);
|
||||
}
|
||||
Assert.Equal(mailMessage.Subject, request.Message.Subject.Data);
|
||||
Assert.Equal(mailMessage.HtmlContent, request.Message.Body.Html.Data);
|
||||
Assert.Equal(mailMessage.TextContent, request.Message.Body.Text.Data);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_sut?.Dispose();
|
||||
}
|
||||
Assert.Single(request.Destination.BccAddresses);
|
||||
Assert.Equal(mailMessage.BccEmails.First(), request.Destination.BccAddresses.First());
|
||||
|
||||
[Fact]
|
||||
public async Task SendEmailAsync_CallsSendEmailAsync_WhenMessageIsValid()
|
||||
{
|
||||
var mailMessage = new MailMessage
|
||||
{
|
||||
ToEmails = new List<string> { "ToEmails" },
|
||||
BccEmails = new List<string> { "BccEmails" },
|
||||
Subject = "Subject",
|
||||
HtmlContent = "HtmlContent",
|
||||
TextContent = "TextContent",
|
||||
Category = "Category"
|
||||
};
|
||||
|
||||
await _sut.SendEmailAsync(mailMessage);
|
||||
|
||||
await _amazonSimpleEmailService.Received(1).SendEmailAsync(
|
||||
Arg.Do<SendEmailRequest>(request =>
|
||||
{
|
||||
Assert.False(string.IsNullOrEmpty(request.Source));
|
||||
|
||||
Assert.Single(request.Destination.ToAddresses);
|
||||
Assert.Equal(mailMessage.ToEmails.First(), request.Destination.ToAddresses.First());
|
||||
|
||||
Assert.Equal(mailMessage.Subject, request.Message.Subject.Data);
|
||||
Assert.Equal(mailMessage.HtmlContent, request.Message.Body.Html.Data);
|
||||
Assert.Equal(mailMessage.TextContent, request.Message.Body.Text.Data);
|
||||
|
||||
Assert.Single(request.Destination.BccAddresses);
|
||||
Assert.Equal(mailMessage.BccEmails.First(), request.Destination.BccAddresses.First());
|
||||
|
||||
Assert.Contains(request.Tags, x => x.Name == "Environment");
|
||||
Assert.Contains(request.Tags, x => x.Name == "Sender");
|
||||
Assert.Contains(request.Tags, x => x.Name == "Category");
|
||||
}));
|
||||
}
|
||||
Assert.Contains(request.Tags, x => x.Name == "Environment");
|
||||
Assert.Contains(request.Tags, x => x.Name == "Sender");
|
||||
Assert.Contains(request.Tags, x => x.Name == "Category");
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -4,74 +4,73 @@ using Bit.Core.Settings;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class AmazonSqsBlockIpServiceTests : IDisposable
|
||||
{
|
||||
public class AmazonSqsBlockIpServiceTests : IDisposable
|
||||
private readonly AmazonSqsBlockIpService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IAmazonSQS _amazonSqs;
|
||||
|
||||
public AmazonSqsBlockIpServiceTests()
|
||||
{
|
||||
private readonly AmazonSqsBlockIpService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IAmazonSQS _amazonSqs;
|
||||
|
||||
public AmazonSqsBlockIpServiceTests()
|
||||
_globalSettings = new GlobalSettings
|
||||
{
|
||||
_globalSettings = new GlobalSettings
|
||||
Amazon =
|
||||
{
|
||||
Amazon =
|
||||
{
|
||||
AccessKeyId = "AccessKeyId-AmazonSesMailDeliveryServiceTests",
|
||||
AccessKeySecret = "AccessKeySecret-AmazonSesMailDeliveryServiceTests",
|
||||
Region = "Region-AmazonSesMailDeliveryServiceTests"
|
||||
}
|
||||
};
|
||||
AccessKeyId = "AccessKeyId-AmazonSesMailDeliveryServiceTests",
|
||||
AccessKeySecret = "AccessKeySecret-AmazonSesMailDeliveryServiceTests",
|
||||
Region = "Region-AmazonSesMailDeliveryServiceTests"
|
||||
}
|
||||
};
|
||||
|
||||
_amazonSqs = Substitute.For<IAmazonSQS>();
|
||||
_amazonSqs = Substitute.For<IAmazonSQS>();
|
||||
|
||||
_sut = new AmazonSqsBlockIpService(_globalSettings, _amazonSqs);
|
||||
}
|
||||
_sut = new AmazonSqsBlockIpService(_globalSettings, _amazonSqs);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_sut?.Dispose();
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
_sut?.Dispose();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BlockIpAsync_UnblockCalled_WhenNotPermanent()
|
||||
{
|
||||
const string expectedIp = "ip";
|
||||
[Fact]
|
||||
public async Task BlockIpAsync_UnblockCalled_WhenNotPermanent()
|
||||
{
|
||||
const string expectedIp = "ip";
|
||||
|
||||
await _sut.BlockIpAsync(expectedIp, false);
|
||||
await _sut.BlockIpAsync(expectedIp, false);
|
||||
|
||||
await _amazonSqs.Received(2).SendMessageAsync(
|
||||
Arg.Any<string>(),
|
||||
Arg.Is(expectedIp));
|
||||
}
|
||||
await _amazonSqs.Received(2).SendMessageAsync(
|
||||
Arg.Any<string>(),
|
||||
Arg.Is(expectedIp));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BlockIpAsync_UnblockNotCalled_WhenPermanent()
|
||||
{
|
||||
const string expectedIp = "ip";
|
||||
[Fact]
|
||||
public async Task BlockIpAsync_UnblockNotCalled_WhenPermanent()
|
||||
{
|
||||
const string expectedIp = "ip";
|
||||
|
||||
await _sut.BlockIpAsync(expectedIp, true);
|
||||
await _sut.BlockIpAsync(expectedIp, true);
|
||||
|
||||
await _amazonSqs.Received(1).SendMessageAsync(
|
||||
Arg.Any<string>(),
|
||||
Arg.Is(expectedIp));
|
||||
}
|
||||
await _amazonSqs.Received(1).SendMessageAsync(
|
||||
Arg.Any<string>(),
|
||||
Arg.Is(expectedIp));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BlockIpAsync_NotBlocked_WhenAlreadyBlockedRecently()
|
||||
{
|
||||
const string expectedIp = "ip";
|
||||
[Fact]
|
||||
public async Task BlockIpAsync_NotBlocked_WhenAlreadyBlockedRecently()
|
||||
{
|
||||
const string expectedIp = "ip";
|
||||
|
||||
await _sut.BlockIpAsync(expectedIp, true);
|
||||
await _sut.BlockIpAsync(expectedIp, true);
|
||||
|
||||
// The second call should hit the already blocked guard clause
|
||||
await _sut.BlockIpAsync(expectedIp, true);
|
||||
// The second call should hit the already blocked guard clause
|
||||
await _sut.BlockIpAsync(expectedIp, true);
|
||||
|
||||
await _amazonSqs.Received(1).SendMessageAsync(
|
||||
Arg.Any<string>(),
|
||||
Arg.Is(expectedIp));
|
||||
}
|
||||
await _amazonSqs.Received(1).SendMessageAsync(
|
||||
Arg.Any<string>(),
|
||||
Arg.Is(expectedIp));
|
||||
}
|
||||
}
|
||||
|
@ -6,36 +6,35 @@ using NSubstitute;
|
||||
using NSubstitute.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class AppleIapServiceTests
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
public class AppleIapServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetReceiptStatusAsync_MoreThanFourAttempts_Throws(SutProvider<AppleIapService> sutProvider)
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetReceiptStatusAsync_MoreThanFourAttempts_Throws(SutProvider<AppleIapService> sutProvider)
|
||||
var result = await sutProvider.Sut.GetReceiptStatusAsync("test", false, 5, null);
|
||||
Assert.Null(result);
|
||||
|
||||
var errorLog = sutProvider.GetDependency<ILogger<AppleIapService>>()
|
||||
.ReceivedCalls()
|
||||
.SingleOrDefault(LogOneWarning);
|
||||
|
||||
Assert.True(errorLog != null, "Must contain one error log of warning level containing 'null'");
|
||||
|
||||
static bool LogOneWarning(ICall call)
|
||||
{
|
||||
var result = await sutProvider.Sut.GetReceiptStatusAsync("test", false, 5, null);
|
||||
Assert.Null(result);
|
||||
|
||||
var errorLog = sutProvider.GetDependency<ILogger<AppleIapService>>()
|
||||
.ReceivedCalls()
|
||||
.SingleOrDefault(LogOneWarning);
|
||||
|
||||
Assert.True(errorLog != null, "Must contain one error log of warning level containing 'null'");
|
||||
|
||||
static bool LogOneWarning(ICall call)
|
||||
if (call.GetMethodInfo().Name != "Log")
|
||||
{
|
||||
if (call.GetMethodInfo().Name != "Log")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var args = call.GetArguments();
|
||||
var logLevel = (LogLevel)args[0];
|
||||
var exception = (Exception)args[3];
|
||||
|
||||
return logLevel == LogLevel.Warning && exception.Message.Contains("null");
|
||||
return false;
|
||||
}
|
||||
|
||||
var args = call.GetArguments();
|
||||
var logLevel = (LogLevel)args[0];
|
||||
var exception = (Exception)args[3];
|
||||
|
||||
return logLevel == LogLevel.Warning && exception.Message.Contains("null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,29 +4,28 @@ using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class AzureAttachmentStorageServiceTests
|
||||
{
|
||||
public class AzureAttachmentStorageServiceTests
|
||||
private readonly AzureAttachmentStorageService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ILogger<AzureAttachmentStorageService> _logger;
|
||||
|
||||
public AzureAttachmentStorageServiceTests()
|
||||
{
|
||||
private readonly AzureAttachmentStorageService _sut;
|
||||
_globalSettings = new GlobalSettings();
|
||||
_logger = Substitute.For<ILogger<AzureAttachmentStorageService>>();
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ILogger<AzureAttachmentStorageService> _logger;
|
||||
_sut = new AzureAttachmentStorageService(_globalSettings, _logger);
|
||||
}
|
||||
|
||||
public AzureAttachmentStorageServiceTests()
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
_logger = Substitute.For<ILogger<AzureAttachmentStorageService>>();
|
||||
|
||||
_sut = new AzureAttachmentStorageService(_globalSettings, _logger);
|
||||
}
|
||||
|
||||
// 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()
|
||||
{
|
||||
Assert.NotNull(_sut);
|
||||
}
|
||||
// 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()
|
||||
{
|
||||
Assert.NotNull(_sut);
|
||||
}
|
||||
}
|
||||
|
@ -2,27 +2,26 @@
|
||||
using Bit.Core.Settings;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class AzureQueueBlockIpServiceTests
|
||||
{
|
||||
public class AzureQueueBlockIpServiceTests
|
||||
private readonly AzureQueueBlockIpService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
public AzureQueueBlockIpServiceTests()
|
||||
{
|
||||
private readonly AzureQueueBlockIpService _sut;
|
||||
_globalSettings = new GlobalSettings();
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
_sut = new AzureQueueBlockIpService(_globalSettings);
|
||||
}
|
||||
|
||||
public AzureQueueBlockIpServiceTests()
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
|
||||
_sut = new AzureQueueBlockIpService(_globalSettings);
|
||||
}
|
||||
|
||||
// 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()
|
||||
{
|
||||
Assert.NotNull(_sut);
|
||||
}
|
||||
// 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()
|
||||
{
|
||||
Assert.NotNull(_sut);
|
||||
}
|
||||
}
|
||||
|
@ -4,31 +4,30 @@ using Bit.Core.Settings;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class AzureQueueEventWriteServiceTests
|
||||
{
|
||||
public class AzureQueueEventWriteServiceTests
|
||||
private readonly AzureQueueEventWriteService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IEventRepository _eventRepository;
|
||||
|
||||
public AzureQueueEventWriteServiceTests()
|
||||
{
|
||||
private readonly AzureQueueEventWriteService _sut;
|
||||
_globalSettings = new GlobalSettings();
|
||||
_eventRepository = Substitute.For<IEventRepository>();
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IEventRepository _eventRepository;
|
||||
_sut = new AzureQueueEventWriteService(
|
||||
_globalSettings
|
||||
);
|
||||
}
|
||||
|
||||
public AzureQueueEventWriteServiceTests()
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
_eventRepository = Substitute.For<IEventRepository>();
|
||||
|
||||
_sut = new AzureQueueEventWriteService(
|
||||
_globalSettings
|
||||
);
|
||||
}
|
||||
|
||||
// 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()
|
||||
{
|
||||
Assert.NotNull(_sut);
|
||||
}
|
||||
// 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()
|
||||
{
|
||||
Assert.NotNull(_sut);
|
||||
}
|
||||
}
|
||||
|
@ -4,32 +4,31 @@ using Microsoft.AspNetCore.Http;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class AzureQueuePushNotificationServiceTests
|
||||
{
|
||||
public class AzureQueuePushNotificationServiceTests
|
||||
private readonly AzureQueuePushNotificationService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public AzureQueuePushNotificationServiceTests()
|
||||
{
|
||||
private readonly AzureQueuePushNotificationService _sut;
|
||||
_globalSettings = new GlobalSettings();
|
||||
_httpContextAccessor = Substitute.For<IHttpContextAccessor>();
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
_sut = new AzureQueuePushNotificationService(
|
||||
_globalSettings,
|
||||
_httpContextAccessor
|
||||
);
|
||||
}
|
||||
|
||||
public AzureQueuePushNotificationServiceTests()
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
_httpContextAccessor = Substitute.For<IHttpContextAccessor>();
|
||||
|
||||
_sut = new AzureQueuePushNotificationService(
|
||||
_globalSettings,
|
||||
_httpContextAccessor
|
||||
);
|
||||
}
|
||||
|
||||
// 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()
|
||||
{
|
||||
Assert.NotNull(_sut);
|
||||
}
|
||||
// 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()
|
||||
{
|
||||
Assert.NotNull(_sut);
|
||||
}
|
||||
}
|
||||
|
@ -9,209 +9,208 @@ using Core.Models.Data;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class CipherServiceTests
|
||||
{
|
||||
public class CipherServiceTests
|
||||
[Theory, UserCipherAutoData]
|
||||
public async Task SaveAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider, Cipher cipher)
|
||||
{
|
||||
[Theory, UserCipherAutoData]
|
||||
public async Task SaveAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider, Cipher cipher)
|
||||
{
|
||||
var lastKnownRevisionDate = cipher.RevisionDate.AddDays(-1);
|
||||
var lastKnownRevisionDate = cipher.RevisionDate.AddDays(-1);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(cipher, cipher.UserId.Value, lastKnownRevisionDate));
|
||||
Assert.Contains("out of date", exception.Message);
|
||||
}
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(cipher, cipher.UserId.Value, lastKnownRevisionDate));
|
||||
Assert.Contains("out of date", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, UserCipherAutoData]
|
||||
public async Task SaveDetailsAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider,
|
||||
CipherDetails cipherDetails)
|
||||
{
|
||||
var lastKnownRevisionDate = cipherDetails.RevisionDate.AddDays(-1);
|
||||
[Theory, UserCipherAutoData]
|
||||
public async Task SaveDetailsAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider,
|
||||
CipherDetails cipherDetails)
|
||||
{
|
||||
var lastKnownRevisionDate = cipherDetails.RevisionDate.AddDays(-1);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveDetailsAsync(cipherDetails, cipherDetails.UserId.Value, lastKnownRevisionDate));
|
||||
Assert.Contains("out of date", exception.Message);
|
||||
}
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveDetailsAsync(cipherDetails, cipherDetails.UserId.Value, lastKnownRevisionDate));
|
||||
Assert.Contains("out of date", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, UserCipherAutoData]
|
||||
public async Task ShareAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider, Cipher cipher,
|
||||
Organization organization, List<Guid> collectionIds)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
var lastKnownRevisionDate = cipher.RevisionDate.AddDays(-1);
|
||||
[Theory, UserCipherAutoData]
|
||||
public async Task ShareAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider, Cipher cipher,
|
||||
Organization organization, List<Guid> collectionIds)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
var lastKnownRevisionDate = cipher.RevisionDate.AddDays(-1);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.ShareAsync(cipher, cipher, organization.Id, collectionIds, cipher.UserId.Value,
|
||||
lastKnownRevisionDate));
|
||||
Assert.Contains("out of date", exception.Message);
|
||||
}
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.ShareAsync(cipher, cipher, organization.Id, collectionIds, cipher.UserId.Value,
|
||||
lastKnownRevisionDate));
|
||||
Assert.Contains("out of date", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, UserCipherAutoData("99ab4f6c-44f8-4ff5-be7a-75c37c33c69e")]
|
||||
public async Task ShareManyAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider,
|
||||
IEnumerable<Cipher> ciphers, Guid organizationId, List<Guid> collectionIds)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId)
|
||||
.Returns(new Organization
|
||||
{
|
||||
PlanType = Enums.PlanType.EnterpriseAnnually,
|
||||
MaxStorageGb = 100
|
||||
});
|
||||
|
||||
var cipherInfos = ciphers.Select(c => (c, (DateTime?)c.RevisionDate.AddDays(-1)));
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.ShareManyAsync(cipherInfos, organizationId, collectionIds, ciphers.First().UserId.Value));
|
||||
Assert.Contains("out of date", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData("")]
|
||||
[InlineUserCipherAutoData("Correct Time")]
|
||||
public async Task SaveAsync_CorrectRevisionDate_Passes(string revisionDateString,
|
||||
SutProvider<CipherService> sutProvider, Cipher cipher)
|
||||
{
|
||||
var lastKnownRevisionDate = string.IsNullOrEmpty(revisionDateString) ? (DateTime?)null : cipher.RevisionDate;
|
||||
|
||||
await sutProvider.Sut.SaveAsync(cipher, cipher.UserId.Value, lastKnownRevisionDate);
|
||||
await sutProvider.GetDependency<ICipherRepository>().Received(1).ReplaceAsync(cipher);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData("")]
|
||||
[InlineUserCipherAutoData("Correct Time")]
|
||||
public async Task SaveDetailsAsync_CorrectRevisionDate_Passes(string revisionDateString,
|
||||
SutProvider<CipherService> sutProvider, CipherDetails cipherDetails)
|
||||
{
|
||||
var lastKnownRevisionDate = string.IsNullOrEmpty(revisionDateString) ? (DateTime?)null : cipherDetails.RevisionDate;
|
||||
|
||||
await sutProvider.Sut.SaveDetailsAsync(cipherDetails, cipherDetails.UserId.Value, lastKnownRevisionDate);
|
||||
await sutProvider.GetDependency<ICipherRepository>().Received(1).ReplaceAsync(cipherDetails);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData("")]
|
||||
[InlineUserCipherAutoData("Correct Time")]
|
||||
public async Task ShareAsync_CorrectRevisionDate_Passes(string revisionDateString,
|
||||
SutProvider<CipherService> sutProvider, Cipher cipher, Organization organization, List<Guid> collectionIds)
|
||||
{
|
||||
var lastKnownRevisionDate = string.IsNullOrEmpty(revisionDateString) ? (DateTime?)null : cipher.RevisionDate;
|
||||
var cipherRepository = sutProvider.GetDependency<ICipherRepository>();
|
||||
cipherRepository.ReplaceAsync(cipher, collectionIds).Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
|
||||
await sutProvider.Sut.ShareAsync(cipher, cipher, organization.Id, collectionIds, cipher.UserId.Value,
|
||||
lastKnownRevisionDate);
|
||||
await cipherRepository.Received(1).ReplaceAsync(cipher, collectionIds);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineKnownUserCipherAutoData(userId: "99ab4f6c-44f8-4ff5-be7a-75c37c33c69e", "")]
|
||||
[InlineKnownUserCipherAutoData(userId: "99ab4f6c-44f8-4ff5-be7a-75c37c33c69e", "CorrectTime")]
|
||||
public async Task ShareManyAsync_CorrectRevisionDate_Passes(string revisionDateString,
|
||||
SutProvider<CipherService> sutProvider, IEnumerable<Cipher> ciphers, Organization organization, List<Guid> collectionIds)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id)
|
||||
.Returns(new Organization
|
||||
{
|
||||
PlanType = Enums.PlanType.EnterpriseAnnually,
|
||||
MaxStorageGb = 100
|
||||
});
|
||||
|
||||
var cipherInfos = ciphers.Select(c => (c,
|
||||
string.IsNullOrEmpty(revisionDateString) ? null : (DateTime?)c.RevisionDate));
|
||||
var sharingUserId = ciphers.First().UserId.Value;
|
||||
|
||||
await sutProvider.Sut.ShareManyAsync(cipherInfos, organization.Id, collectionIds, sharingUserId);
|
||||
await sutProvider.GetDependency<ICipherRepository>().Received(1).UpdateCiphersAsync(sharingUserId,
|
||||
Arg.Is<IEnumerable<Cipher>>(arg => arg.Except(ciphers).IsNullOrEmpty()));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineKnownUserCipherAutoData("c64d8a15-606e-41d6-9c7e-174d4d8f3b2e", "c64d8a15-606e-41d6-9c7e-174d4d8f3b2e")]
|
||||
[InlineOrganizationCipherAutoData("c64d8a15-606e-41d6-9c7e-174d4d8f3b2e")]
|
||||
public async Task RestoreAsync_UpdatesCipher(Guid restoringUserId, Cipher cipher, SutProvider<CipherService> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICipherRepository>().GetCanEditByIdAsync(restoringUserId, cipher.Id).Returns(true);
|
||||
|
||||
var initialRevisionDate = new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
cipher.DeletedDate = initialRevisionDate;
|
||||
cipher.RevisionDate = initialRevisionDate;
|
||||
|
||||
await sutProvider.Sut.RestoreAsync(cipher, restoringUserId, cipher.OrganizationId.HasValue);
|
||||
|
||||
Assert.Null(cipher.DeletedDate);
|
||||
Assert.NotEqual(initialRevisionDate, cipher.RevisionDate);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineKnownUserCipherAutoData("c64d8a15-606e-41d6-9c7e-174d4d8f3b2e", "c64d8a15-606e-41d6-9c7e-174d4d8f3b2e")]
|
||||
public async Task RestoreManyAsync_UpdatesCiphers(Guid restoringUserId, IEnumerable<CipherDetails> ciphers,
|
||||
SutProvider<CipherService> sutProvider)
|
||||
{
|
||||
var previousRevisionDate = DateTime.UtcNow;
|
||||
foreach (var cipher in ciphers)
|
||||
[Theory, UserCipherAutoData("99ab4f6c-44f8-4ff5-be7a-75c37c33c69e")]
|
||||
public async Task ShareManyAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider,
|
||||
IEnumerable<Cipher> ciphers, Guid organizationId, List<Guid> collectionIds)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId)
|
||||
.Returns(new Organization
|
||||
{
|
||||
cipher.RevisionDate = previousRevisionDate;
|
||||
}
|
||||
|
||||
var revisionDate = previousRevisionDate + TimeSpan.FromMinutes(1);
|
||||
sutProvider.GetDependency<ICipherRepository>().RestoreAsync(Arg.Any<IEnumerable<Guid>>(), restoringUserId)
|
||||
.Returns(revisionDate);
|
||||
|
||||
await sutProvider.Sut.RestoreManyAsync(ciphers, restoringUserId);
|
||||
|
||||
foreach (var cipher in ciphers)
|
||||
{
|
||||
Assert.Null(cipher.DeletedDate);
|
||||
Assert.Equal(revisionDate, cipher.RevisionDate);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData]
|
||||
public async Task ShareManyAsync_FreeOrgWithAttachment_Throws(SutProvider<CipherService> sutProvider,
|
||||
IEnumerable<Cipher> ciphers, Guid organizationId, List<Guid> collectionIds)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId).Returns(new Organization
|
||||
{
|
||||
PlanType = Enums.PlanType.Free
|
||||
PlanType = Enums.PlanType.EnterpriseAnnually,
|
||||
MaxStorageGb = 100
|
||||
});
|
||||
ciphers.FirstOrDefault().Attachments =
|
||||
"{\"attachment1\":{\"Size\":\"250\",\"FileName\":\"superCoolFile\","
|
||||
+ "\"Key\":\"superCoolFile\",\"ContainerName\":\"testContainer\",\"Validated\":false}}";
|
||||
|
||||
var cipherInfos = ciphers.Select(c => (c,
|
||||
(DateTime?)c.RevisionDate));
|
||||
var sharingUserId = ciphers.First().UserId.Value;
|
||||
var cipherInfos = ciphers.Select(c => (c, (DateTime?)c.RevisionDate.AddDays(-1)));
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.ShareManyAsync(cipherInfos, organizationId, collectionIds, sharingUserId));
|
||||
Assert.Contains("This organization cannot use attachments", exception.Message);
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.ShareManyAsync(cipherInfos, organizationId, collectionIds, ciphers.First().UserId.Value));
|
||||
Assert.Contains("out of date", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData("")]
|
||||
[InlineUserCipherAutoData("Correct Time")]
|
||||
public async Task SaveAsync_CorrectRevisionDate_Passes(string revisionDateString,
|
||||
SutProvider<CipherService> sutProvider, Cipher cipher)
|
||||
{
|
||||
var lastKnownRevisionDate = string.IsNullOrEmpty(revisionDateString) ? (DateTime?)null : cipher.RevisionDate;
|
||||
|
||||
await sutProvider.Sut.SaveAsync(cipher, cipher.UserId.Value, lastKnownRevisionDate);
|
||||
await sutProvider.GetDependency<ICipherRepository>().Received(1).ReplaceAsync(cipher);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData("")]
|
||||
[InlineUserCipherAutoData("Correct Time")]
|
||||
public async Task SaveDetailsAsync_CorrectRevisionDate_Passes(string revisionDateString,
|
||||
SutProvider<CipherService> sutProvider, CipherDetails cipherDetails)
|
||||
{
|
||||
var lastKnownRevisionDate = string.IsNullOrEmpty(revisionDateString) ? (DateTime?)null : cipherDetails.RevisionDate;
|
||||
|
||||
await sutProvider.Sut.SaveDetailsAsync(cipherDetails, cipherDetails.UserId.Value, lastKnownRevisionDate);
|
||||
await sutProvider.GetDependency<ICipherRepository>().Received(1).ReplaceAsync(cipherDetails);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData("")]
|
||||
[InlineUserCipherAutoData("Correct Time")]
|
||||
public async Task ShareAsync_CorrectRevisionDate_Passes(string revisionDateString,
|
||||
SutProvider<CipherService> sutProvider, Cipher cipher, Organization organization, List<Guid> collectionIds)
|
||||
{
|
||||
var lastKnownRevisionDate = string.IsNullOrEmpty(revisionDateString) ? (DateTime?)null : cipher.RevisionDate;
|
||||
var cipherRepository = sutProvider.GetDependency<ICipherRepository>();
|
||||
cipherRepository.ReplaceAsync(cipher, collectionIds).Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
|
||||
await sutProvider.Sut.ShareAsync(cipher, cipher, organization.Id, collectionIds, cipher.UserId.Value,
|
||||
lastKnownRevisionDate);
|
||||
await cipherRepository.Received(1).ReplaceAsync(cipher, collectionIds);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineKnownUserCipherAutoData(userId: "99ab4f6c-44f8-4ff5-be7a-75c37c33c69e", "")]
|
||||
[InlineKnownUserCipherAutoData(userId: "99ab4f6c-44f8-4ff5-be7a-75c37c33c69e", "CorrectTime")]
|
||||
public async Task ShareManyAsync_CorrectRevisionDate_Passes(string revisionDateString,
|
||||
SutProvider<CipherService> sutProvider, IEnumerable<Cipher> ciphers, Organization organization, List<Guid> collectionIds)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id)
|
||||
.Returns(new Organization
|
||||
{
|
||||
PlanType = Enums.PlanType.EnterpriseAnnually,
|
||||
MaxStorageGb = 100
|
||||
});
|
||||
|
||||
var cipherInfos = ciphers.Select(c => (c,
|
||||
string.IsNullOrEmpty(revisionDateString) ? null : (DateTime?)c.RevisionDate));
|
||||
var sharingUserId = ciphers.First().UserId.Value;
|
||||
|
||||
await sutProvider.Sut.ShareManyAsync(cipherInfos, organization.Id, collectionIds, sharingUserId);
|
||||
await sutProvider.GetDependency<ICipherRepository>().Received(1).UpdateCiphersAsync(sharingUserId,
|
||||
Arg.Is<IEnumerable<Cipher>>(arg => arg.Except(ciphers).IsNullOrEmpty()));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineKnownUserCipherAutoData("c64d8a15-606e-41d6-9c7e-174d4d8f3b2e", "c64d8a15-606e-41d6-9c7e-174d4d8f3b2e")]
|
||||
[InlineOrganizationCipherAutoData("c64d8a15-606e-41d6-9c7e-174d4d8f3b2e")]
|
||||
public async Task RestoreAsync_UpdatesCipher(Guid restoringUserId, Cipher cipher, SutProvider<CipherService> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICipherRepository>().GetCanEditByIdAsync(restoringUserId, cipher.Id).Returns(true);
|
||||
|
||||
var initialRevisionDate = new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
cipher.DeletedDate = initialRevisionDate;
|
||||
cipher.RevisionDate = initialRevisionDate;
|
||||
|
||||
await sutProvider.Sut.RestoreAsync(cipher, restoringUserId, cipher.OrganizationId.HasValue);
|
||||
|
||||
Assert.Null(cipher.DeletedDate);
|
||||
Assert.NotEqual(initialRevisionDate, cipher.RevisionDate);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineKnownUserCipherAutoData("c64d8a15-606e-41d6-9c7e-174d4d8f3b2e", "c64d8a15-606e-41d6-9c7e-174d4d8f3b2e")]
|
||||
public async Task RestoreManyAsync_UpdatesCiphers(Guid restoringUserId, IEnumerable<CipherDetails> ciphers,
|
||||
SutProvider<CipherService> sutProvider)
|
||||
{
|
||||
var previousRevisionDate = DateTime.UtcNow;
|
||||
foreach (var cipher in ciphers)
|
||||
{
|
||||
cipher.RevisionDate = previousRevisionDate;
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData]
|
||||
public async Task ShareManyAsync_PaidOrgWithAttachment_Passes(SutProvider<CipherService> sutProvider,
|
||||
IEnumerable<Cipher> ciphers, Guid organizationId, List<Guid> collectionIds)
|
||||
var revisionDate = previousRevisionDate + TimeSpan.FromMinutes(1);
|
||||
sutProvider.GetDependency<ICipherRepository>().RestoreAsync(Arg.Any<IEnumerable<Guid>>(), restoringUserId)
|
||||
.Returns(revisionDate);
|
||||
|
||||
await sutProvider.Sut.RestoreManyAsync(ciphers, restoringUserId);
|
||||
|
||||
foreach (var cipher in ciphers)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId)
|
||||
.Returns(new Organization
|
||||
{
|
||||
PlanType = Enums.PlanType.EnterpriseAnnually,
|
||||
MaxStorageGb = 100
|
||||
});
|
||||
ciphers.FirstOrDefault().Attachments =
|
||||
"{\"attachment1\":{\"Size\":\"250\",\"FileName\":\"superCoolFile\","
|
||||
+ "\"Key\":\"superCoolFile\",\"ContainerName\":\"testContainer\",\"Validated\":false}}";
|
||||
|
||||
var cipherInfos = ciphers.Select(c => (c,
|
||||
(DateTime?)c.RevisionDate));
|
||||
var sharingUserId = ciphers.First().UserId.Value;
|
||||
|
||||
await sutProvider.Sut.ShareManyAsync(cipherInfos, organizationId, collectionIds, sharingUserId);
|
||||
await sutProvider.GetDependency<ICipherRepository>().Received(1).UpdateCiphersAsync(sharingUserId,
|
||||
Arg.Is<IEnumerable<Cipher>>(arg => arg.Except(ciphers).IsNullOrEmpty()));
|
||||
Assert.Null(cipher.DeletedDate);
|
||||
Assert.Equal(revisionDate, cipher.RevisionDate);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData]
|
||||
public async Task ShareManyAsync_FreeOrgWithAttachment_Throws(SutProvider<CipherService> sutProvider,
|
||||
IEnumerable<Cipher> ciphers, Guid organizationId, List<Guid> collectionIds)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId).Returns(new Organization
|
||||
{
|
||||
PlanType = Enums.PlanType.Free
|
||||
});
|
||||
ciphers.FirstOrDefault().Attachments =
|
||||
"{\"attachment1\":{\"Size\":\"250\",\"FileName\":\"superCoolFile\","
|
||||
+ "\"Key\":\"superCoolFile\",\"ContainerName\":\"testContainer\",\"Validated\":false}}";
|
||||
|
||||
var cipherInfos = ciphers.Select(c => (c,
|
||||
(DateTime?)c.RevisionDate));
|
||||
var sharingUserId = ciphers.First().UserId.Value;
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.ShareManyAsync(cipherInfos, organizationId, collectionIds, sharingUserId));
|
||||
Assert.Contains("This organization cannot use attachments", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData]
|
||||
public async Task ShareManyAsync_PaidOrgWithAttachment_Passes(SutProvider<CipherService> sutProvider,
|
||||
IEnumerable<Cipher> ciphers, Guid organizationId, List<Guid> collectionIds)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId)
|
||||
.Returns(new Organization
|
||||
{
|
||||
PlanType = Enums.PlanType.EnterpriseAnnually,
|
||||
MaxStorageGb = 100
|
||||
});
|
||||
ciphers.FirstOrDefault().Attachments =
|
||||
"{\"attachment1\":{\"Size\":\"250\",\"FileName\":\"superCoolFile\","
|
||||
+ "\"Key\":\"superCoolFile\",\"ContainerName\":\"testContainer\",\"Validated\":false}}";
|
||||
|
||||
var cipherInfos = ciphers.Select(c => (c,
|
||||
(DateTime?)c.RevisionDate));
|
||||
var sharingUserId = ciphers.First().UserId.Value;
|
||||
|
||||
await sutProvider.Sut.ShareManyAsync(cipherInfos, organizationId, collectionIds, sharingUserId);
|
||||
await sutProvider.GetDependency<ICipherRepository>().Received(1).UpdateCiphersAsync(sharingUserId,
|
||||
Arg.Is<IEnumerable<Cipher>>(arg => arg.Except(ciphers).IsNullOrEmpty()));
|
||||
}
|
||||
}
|
||||
|
@ -10,161 +10,160 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class CollectionServiceTest
|
||||
{
|
||||
public class CollectionServiceTest
|
||||
[Theory, CollectionAutoData]
|
||||
public async Task SaveAsync_DefaultId_CreatesCollectionInTheRepository(Collection collection, Organization organization, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
[Theory, CollectionAutoData]
|
||||
public async Task SaveAsync_DefaultId_CreatesCollectionInTheRepository(Collection collection, Organization organization, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
collection.Id = default;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
collection.Id = default;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
await sutProvider.Sut.SaveAsync(collection);
|
||||
await sutProvider.Sut.SaveAsync(collection);
|
||||
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
[Theory, CollectionAutoData]
|
||||
public async Task SaveAsync_DefaultIdWithGroups_CreateCollectionWithGroupsInRepository(Collection collection,
|
||||
IEnumerable<SelectionReadOnly> groups, Organization organization, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
collection.Id = default;
|
||||
organization.UseGroups = true;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
[Theory, CollectionAutoData]
|
||||
public async Task SaveAsync_DefaultIdWithGroups_CreateCollectionWithGroupsInRepository(Collection collection,
|
||||
IEnumerable<SelectionReadOnly> groups, Organization organization, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
collection.Id = default;
|
||||
organization.UseGroups = true;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
await sutProvider.Sut.SaveAsync(collection, groups);
|
||||
await sutProvider.Sut.SaveAsync(collection, groups);
|
||||
|
||||
await sutProvider.GetDependency<ICollectionRepository>().Received().CreateAsync(collection, groups);
|
||||
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));
|
||||
}
|
||||
await sutProvider.GetDependency<ICollectionRepository>().Received().CreateAsync(collection, groups);
|
||||
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));
|
||||
}
|
||||
|
||||
[Theory, CollectionAutoData]
|
||||
public async Task SaveAsync_NonDefaultId_ReplacesCollectionInRepository(Collection collection, Organization organization, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
var creationDate = collection.CreationDate;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
[Theory, CollectionAutoData]
|
||||
public async Task SaveAsync_NonDefaultId_ReplacesCollectionInRepository(Collection collection, Organization organization, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
var creationDate = collection.CreationDate;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
await sutProvider.Sut.SaveAsync(collection);
|
||||
await sutProvider.Sut.SaveAsync(collection);
|
||||
|
||||
await sutProvider.GetDependency<ICollectionRepository>().Received().ReplaceAsync(collection);
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogCollectionEventAsync(collection, EventType.Collection_Updated);
|
||||
Assert.Equal(collection.CreationDate, creationDate);
|
||||
Assert.True(collection.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
await sutProvider.GetDependency<ICollectionRepository>().Received().ReplaceAsync(collection);
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogCollectionEventAsync(collection, EventType.Collection_Updated);
|
||||
Assert.Equal(collection.CreationDate, creationDate);
|
||||
Assert.True(collection.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Theory, CollectionAutoData]
|
||||
public async Task SaveAsync_OrganizationNotUseGroup_CreateCollectionWithoutGroupsInRepository(Collection collection, IEnumerable<SelectionReadOnly> groups,
|
||||
Organization organization, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
collection.Id = default;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
[Theory, CollectionAutoData]
|
||||
public async Task SaveAsync_OrganizationNotUseGroup_CreateCollectionWithoutGroupsInRepository(Collection collection, IEnumerable<SelectionReadOnly> groups,
|
||||
Organization organization, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
collection.Id = default;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
await sutProvider.Sut.SaveAsync(collection, groups);
|
||||
await sutProvider.Sut.SaveAsync(collection, groups);
|
||||
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
[Theory, CollectionAutoData]
|
||||
public async Task SaveAsync_DefaultIdWithUserId_UpdateUserInCollectionRepository(Collection collection,
|
||||
Organization organization, OrganizationUser organizationUser, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
collection.Id = default;
|
||||
organizationUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByOrganizationAsync(organization.Id, organizationUser.Id)
|
||||
.Returns(organizationUser);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
[Theory, CollectionAutoData]
|
||||
public async Task SaveAsync_DefaultIdWithUserId_UpdateUserInCollectionRepository(Collection collection,
|
||||
Organization organization, OrganizationUser organizationUser, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
collection.Id = default;
|
||||
organizationUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByOrganizationAsync(organization.Id, organizationUser.Id)
|
||||
.Returns(organizationUser);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
await sutProvider.Sut.SaveAsync(collection, null, organizationUser.Id);
|
||||
await sutProvider.Sut.SaveAsync(collection, null, organizationUser.Id);
|
||||
|
||||
await sutProvider.GetDependency<ICollectionRepository>().Received().CreateAsync(collection);
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>().Received()
|
||||
.GetByOrganizationAsync(organization.Id, organizationUser.Id);
|
||||
await sutProvider.GetDependency<ICollectionRepository>().Received().UpdateUsersAsync(collection.Id, Arg.Any<List<SelectionReadOnly>>());
|
||||
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));
|
||||
}
|
||||
await sutProvider.GetDependency<ICollectionRepository>().Received().CreateAsync(collection);
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>().Received()
|
||||
.GetByOrganizationAsync(organization.Id, organizationUser.Id);
|
||||
await sutProvider.GetDependency<ICollectionRepository>().Received().UpdateUsersAsync(collection.Id, Arg.Any<List<SelectionReadOnly>>());
|
||||
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));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_NonExistingOrganizationId_ThrowsBadRequest(Collection collection, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
var ex = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SaveAsync(collection));
|
||||
Assert.Contains("Organization not found", 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);
|
||||
}
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_NonExistingOrganizationId_ThrowsBadRequest(Collection collection, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
var ex = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SaveAsync(collection));
|
||||
Assert.Contains("Organization not found", 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);
|
||||
}
|
||||
|
||||
[Theory, CollectionAutoData]
|
||||
public async Task SaveAsync_ExceedsOrganizationMaxCollections_ThrowsBadRequest(Collection collection, Organization organization, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
collection.Id = default;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
sutProvider.GetDependency<ICollectionRepository>().GetCountByOrganizationIdAsync(organization.Id)
|
||||
.Returns(organization.MaxCollections.Value);
|
||||
[Theory, CollectionAutoData]
|
||||
public async Task SaveAsync_ExceedsOrganizationMaxCollections_ThrowsBadRequest(Collection collection, Organization organization, SutProvider<CollectionService> sutProvider)
|
||||
{
|
||||
collection.Id = default;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
sutProvider.GetDependency<ICollectionRepository>().GetCountByOrganizationIdAsync(organization.Id)
|
||||
.Returns(organization.MaxCollections.Value);
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
[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);
|
||||
[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.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);
|
||||
}
|
||||
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);
|
||||
[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
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.DeleteUserAsync(collection, Guid.NewGuid()));
|
||||
await sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs().DeleteUserAsync(default, default);
|
||||
await sutProvider.GetDependency<IEventService>().DidNotReceiveWithAnyArgs()
|
||||
.LogOrganizationUserEventAsync(default, default);
|
||||
}
|
||||
// user not in organization
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.DeleteUserAsync(collection, organizationUser.Id));
|
||||
// invalid user
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.DeleteUserAsync(collection, Guid.NewGuid()));
|
||||
await sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs().DeleteUserAsync(default, default);
|
||||
await sutProvider.GetDependency<IEventService>().DidNotReceiveWithAnyArgs()
|
||||
.LogOrganizationUserEventAsync(default, default);
|
||||
}
|
||||
}
|
||||
|
@ -5,33 +5,32 @@ using Bit.Core.Services;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class DeviceServiceTests
|
||||
{
|
||||
public class DeviceServiceTests
|
||||
[Fact]
|
||||
public async Task DeviceSaveShouldUpdateRevisionDateAndPushRegistration()
|
||||
{
|
||||
[Fact]
|
||||
public async Task DeviceSaveShouldUpdateRevisionDateAndPushRegistration()
|
||||
var deviceRepo = Substitute.For<IDeviceRepository>();
|
||||
var pushRepo = Substitute.For<IPushRegistrationService>();
|
||||
var deviceService = new DeviceService(deviceRepo, pushRepo);
|
||||
|
||||
var id = Guid.NewGuid();
|
||||
var userId = Guid.NewGuid();
|
||||
var device = new Device
|
||||
{
|
||||
var deviceRepo = Substitute.For<IDeviceRepository>();
|
||||
var pushRepo = Substitute.For<IPushRegistrationService>();
|
||||
var deviceService = new DeviceService(deviceRepo, pushRepo);
|
||||
Id = id,
|
||||
Name = "test device",
|
||||
Type = DeviceType.Android,
|
||||
UserId = userId,
|
||||
PushToken = "testtoken",
|
||||
Identifier = "testid"
|
||||
};
|
||||
await deviceService.SaveAsync(device);
|
||||
|
||||
var id = Guid.NewGuid();
|
||||
var userId = Guid.NewGuid();
|
||||
var device = new Device
|
||||
{
|
||||
Id = id,
|
||||
Name = "test device",
|
||||
Type = DeviceType.Android,
|
||||
UserId = userId,
|
||||
PushToken = "testtoken",
|
||||
Identifier = "testid"
|
||||
};
|
||||
await deviceService.SaveAsync(device);
|
||||
|
||||
Assert.True(device.RevisionDate - DateTime.UtcNow < TimeSpan.FromSeconds(1));
|
||||
await pushRepo.Received().CreateOrUpdateRegistrationAsync("testtoken", id.ToString(),
|
||||
userId.ToString(), "testid", DeviceType.Android);
|
||||
}
|
||||
Assert.True(device.RevisionDate - DateTime.UtcNow < TimeSpan.FromSeconds(1));
|
||||
await pushRepo.Received().CreateOrUpdateRegistrationAsync("testtoken", id.ToString(),
|
||||
userId.ToString(), "testid", DeviceType.Android);
|
||||
}
|
||||
}
|
||||
|
@ -9,163 +9,162 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class EmergencyAccessServiceTests
|
||||
{
|
||||
public class EmergencyAccessServiceTests
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_PremiumCannotUpdate(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User savingUser)
|
||||
{
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_PremiumCannotUpdate(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User savingUser)
|
||||
savingUser.Premium = false;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
savingUser.Premium = false;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
GrantorId = savingUser.Id,
|
||||
};
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
GrantorId = savingUser.Id,
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(savingUser.Id).Returns(savingUser);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(savingUser.Id).Returns(savingUser);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(emergencyAccess, savingUser));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(emergencyAccess, savingUser));
|
||||
|
||||
Assert.Contains("Not a premium user.", exception.Message);
|
||||
await sutProvider.GetDependency<IEmergencyAccessRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
|
||||
}
|
||||
Assert.Contains("Not a premium user.", exception.Message);
|
||||
await sutProvider.GetDependency<IEmergencyAccessRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task InviteAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User invitingUser, string email, int waitTime)
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task InviteAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User invitingUser, string email, int waitTime)
|
||||
{
|
||||
invitingUser.UsesKeyConnector = true;
|
||||
sutProvider.GetDependency<IUserService>().CanAccessPremium(invitingUser).Returns(true);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.InviteAsync(invitingUser, email, Enums.EmergencyAccessType.Takeover, waitTime));
|
||||
|
||||
Assert.Contains("You cannot use Emergency Access Takeover because you are using Key Connector", exception.Message);
|
||||
await sutProvider.GetDependency<IEmergencyAccessRepository>().DidNotReceiveWithAnyArgs().CreateAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task ConfirmUserAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User confirmingUser, string key)
|
||||
{
|
||||
confirmingUser.UsesKeyConnector = true;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
invitingUser.UsesKeyConnector = true;
|
||||
sutProvider.GetDependency<IUserService>().CanAccessPremium(invitingUser).Returns(true);
|
||||
Status = Enums.EmergencyAccessStatusType.Accepted,
|
||||
GrantorId = confirmingUser.Id,
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
};
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.InviteAsync(invitingUser, email, Enums.EmergencyAccessType.Takeover, waitTime));
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(confirmingUser.Id).Returns(confirmingUser);
|
||||
sutProvider.GetDependency<IEmergencyAccessRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(emergencyAccess);
|
||||
|
||||
Assert.Contains("You cannot use Emergency Access Takeover because you are using Key Connector", exception.Message);
|
||||
await sutProvider.GetDependency<IEmergencyAccessRepository>().DidNotReceiveWithAnyArgs().CreateAsync(default);
|
||||
}
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.ConfirmUserAsync(new Guid(), key, confirmingUser.Id));
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task ConfirmUserAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User confirmingUser, string key)
|
||||
Assert.Contains("You cannot use Emergency Access Takeover because you are using Key Connector", exception.Message);
|
||||
await sutProvider.GetDependency<IEmergencyAccessRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User savingUser)
|
||||
{
|
||||
savingUser.UsesKeyConnector = true;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
confirmingUser.UsesKeyConnector = true;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
Status = Enums.EmergencyAccessStatusType.Accepted,
|
||||
GrantorId = confirmingUser.Id,
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
};
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
GrantorId = savingUser.Id,
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(confirmingUser.Id).Returns(confirmingUser);
|
||||
sutProvider.GetDependency<IEmergencyAccessRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(emergencyAccess);
|
||||
var userService = sutProvider.GetDependency<IUserService>();
|
||||
userService.GetUserByIdAsync(savingUser.Id).Returns(savingUser);
|
||||
userService.CanAccessPremium(savingUser).Returns(true);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.ConfirmUserAsync(new Guid(), key, confirmingUser.Id));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(emergencyAccess, savingUser));
|
||||
|
||||
Assert.Contains("You cannot use Emergency Access Takeover because you are using Key Connector", exception.Message);
|
||||
await sutProvider.GetDependency<IEmergencyAccessRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
|
||||
}
|
||||
Assert.Contains("You cannot use Emergency Access Takeover because you are using Key Connector", exception.Message);
|
||||
await sutProvider.GetDependency<IEmergencyAccessRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User savingUser)
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task InitiateAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User initiatingUser, User grantor)
|
||||
{
|
||||
grantor.UsesKeyConnector = true;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
savingUser.UsesKeyConnector = true;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
GrantorId = savingUser.Id,
|
||||
};
|
||||
Status = Enums.EmergencyAccessStatusType.Confirmed,
|
||||
GranteeId = initiatingUser.Id,
|
||||
GrantorId = grantor.Id,
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
};
|
||||
|
||||
var userService = sutProvider.GetDependency<IUserService>();
|
||||
userService.GetUserByIdAsync(savingUser.Id).Returns(savingUser);
|
||||
userService.CanAccessPremium(savingUser).Returns(true);
|
||||
sutProvider.GetDependency<IEmergencyAccessRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(emergencyAccess);
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(grantor.Id).Returns(grantor);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(emergencyAccess, savingUser));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.InitiateAsync(new Guid(), initiatingUser));
|
||||
|
||||
Assert.Contains("You cannot use Emergency Access Takeover because you are using Key Connector", exception.Message);
|
||||
await sutProvider.GetDependency<IEmergencyAccessRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
|
||||
}
|
||||
Assert.Contains("You cannot takeover an account that is using Key Connector", exception.Message);
|
||||
await sutProvider.GetDependency<IEmergencyAccessRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task InitiateAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User initiatingUser, User grantor)
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task TakeoverAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User requestingUser, User grantor)
|
||||
{
|
||||
grantor.UsesKeyConnector = true;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
grantor.UsesKeyConnector = true;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
Status = Enums.EmergencyAccessStatusType.Confirmed,
|
||||
GranteeId = initiatingUser.Id,
|
||||
GrantorId = grantor.Id,
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
};
|
||||
GrantorId = grantor.Id,
|
||||
GranteeId = requestingUser.Id,
|
||||
Status = Enums.EmergencyAccessStatusType.RecoveryApproved,
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IEmergencyAccessRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(emergencyAccess);
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(grantor.Id).Returns(grantor);
|
||||
sutProvider.GetDependency<IEmergencyAccessRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(emergencyAccess);
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(grantor.Id).Returns(grantor);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.InitiateAsync(new Guid(), initiatingUser));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.TakeoverAsync(new Guid(), requestingUser));
|
||||
|
||||
Assert.Contains("You cannot takeover an account that is using Key Connector", exception.Message);
|
||||
await sutProvider.GetDependency<IEmergencyAccessRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
|
||||
}
|
||||
Assert.Contains("You cannot takeover an account that is using Key Connector", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task TakeoverAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User requestingUser, User grantor)
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task PasswordAsync_Disables_2FA_Providers_And_Unknown_Device_Verification_On_The_Grantor(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User requestingUser, User grantor)
|
||||
{
|
||||
grantor.UsesKeyConnector = true;
|
||||
grantor.UnknownDeviceVerificationEnabled = true;
|
||||
grantor.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
{
|
||||
grantor.UsesKeyConnector = true;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
{
|
||||
GrantorId = grantor.Id,
|
||||
GranteeId = requestingUser.Id,
|
||||
Status = Enums.EmergencyAccessStatusType.RecoveryApproved,
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IEmergencyAccessRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(emergencyAccess);
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(grantor.Id).Returns(grantor);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.TakeoverAsync(new Guid(), requestingUser));
|
||||
|
||||
Assert.Contains("You cannot takeover an account that is using Key Connector", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task PasswordAsync_Disables_2FA_Providers_And_Unknown_Device_Verification_On_The_Grantor(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User requestingUser, User grantor)
|
||||
MetaData = new Dictionary<string, object> { ["Email"] = "asdfasf" },
|
||||
Enabled = true
|
||||
}
|
||||
});
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
grantor.UsesKeyConnector = true;
|
||||
grantor.UnknownDeviceVerificationEnabled = true;
|
||||
grantor.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
{
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
{
|
||||
MetaData = new Dictionary<string, object> { ["Email"] = "asdfasf" },
|
||||
Enabled = true
|
||||
}
|
||||
});
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
GrantorId = grantor.Id,
|
||||
GranteeId = requestingUser.Id,
|
||||
Status = Enums.EmergencyAccessStatusType.RecoveryApproved,
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
};
|
||||
GrantorId = grantor.Id,
|
||||
GranteeId = requestingUser.Id,
|
||||
Status = Enums.EmergencyAccessStatusType.RecoveryApproved,
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IEmergencyAccessRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(emergencyAccess);
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(grantor.Id).Returns(grantor);
|
||||
sutProvider.GetDependency<IEmergencyAccessRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(emergencyAccess);
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(grantor.Id).Returns(grantor);
|
||||
|
||||
await sutProvider.Sut.PasswordAsync(Guid.NewGuid(), requestingUser, "blablahash", "blablakey");
|
||||
await sutProvider.Sut.PasswordAsync(Guid.NewGuid(), requestingUser, "blablahash", "blablakey");
|
||||
|
||||
Assert.False(grantor.UnknownDeviceVerificationEnabled);
|
||||
Assert.Empty(grantor.GetTwoFactorProviders());
|
||||
await sutProvider.GetDependency<IUserRepository>().Received().ReplaceAsync(grantor);
|
||||
}
|
||||
Assert.False(grantor.UnknownDeviceVerificationEnabled);
|
||||
Assert.Empty(grantor.GetTwoFactorProviders());
|
||||
await sutProvider.GetDependency<IUserRepository>().Received().ReplaceAsync(grantor);
|
||||
}
|
||||
}
|
||||
|
@ -11,99 +11,98 @@ using Bit.Test.Common.Helpers;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class EventServiceTests
|
||||
{
|
||||
[SutProviderCustomize]
|
||||
public class EventServiceTests
|
||||
public static IEnumerable<object[]> InstallationIdTestCases => TestCaseHelper.GetCombinationsOfMultipleLists(
|
||||
new object[] { Guid.NewGuid(), null },
|
||||
Enum.GetValues<EventType>().Select(e => (object)e)
|
||||
).Select(p => p.ToArray());
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(InstallationIdTestCases))]
|
||||
public async Task LogOrganizationEvent_ProvidesInstallationId(Guid? installationId, EventType eventType,
|
||||
Organization organization, SutProvider<EventService> sutProvider)
|
||||
{
|
||||
public static IEnumerable<object[]> InstallationIdTestCases => TestCaseHelper.GetCombinationsOfMultipleLists(
|
||||
new object[] { Guid.NewGuid(), null },
|
||||
Enum.GetValues<EventType>().Select(e => (object)e)
|
||||
).Select(p => p.ToArray());
|
||||
organization.Enabled = true;
|
||||
organization.UseEvents = true;
|
||||
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(InstallationIdTestCases))]
|
||||
public async Task LogOrganizationEvent_ProvidesInstallationId(Guid? installationId, EventType eventType,
|
||||
Organization organization, SutProvider<EventService> sutProvider)
|
||||
sutProvider.GetDependency<ICurrentContext>().InstallationId.Returns(installationId);
|
||||
|
||||
await sutProvider.Sut.LogOrganizationEventAsync(organization, eventType);
|
||||
|
||||
await sutProvider.GetDependency<IEventWriteService>().Received(1).CreateAsync(Arg.Is<IEvent>(e =>
|
||||
e.OrganizationId == organization.Id &&
|
||||
e.Type == eventType &&
|
||||
e.InstallationId == installationId));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task LogOrganizationUserEvent_LogsRequiredInfo(OrganizationUser orgUser, EventType eventType, DateTime date,
|
||||
Guid actingUserId, Guid providerId, string ipAddress, DeviceType deviceType, SutProvider<EventService> sutProvider)
|
||||
{
|
||||
var orgAbilities = new Dictionary<Guid, OrganizationAbility>()
|
||||
{
|
||||
organization.Enabled = true;
|
||||
organization.UseEvents = true;
|
||||
{orgUser.OrganizationId, new OrganizationAbility() { UseEvents = true, Enabled = true } }
|
||||
};
|
||||
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilitiesAsync().Returns(orgAbilities);
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||
sutProvider.GetDependency<ICurrentContext>().IpAddress.Returns(ipAddress);
|
||||
sutProvider.GetDependency<ICurrentContext>().DeviceType.Returns(deviceType);
|
||||
sutProvider.GetDependency<ICurrentContext>().ProviderIdForOrg(Arg.Any<Guid>()).Returns(providerId);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().InstallationId.Returns(installationId);
|
||||
await sutProvider.Sut.LogOrganizationUserEventAsync(orgUser, eventType, date);
|
||||
|
||||
await sutProvider.Sut.LogOrganizationEventAsync(organization, eventType);
|
||||
|
||||
await sutProvider.GetDependency<IEventWriteService>().Received(1).CreateAsync(Arg.Is<IEvent>(e =>
|
||||
e.OrganizationId == organization.Id &&
|
||||
e.Type == eventType &&
|
||||
e.InstallationId == installationId));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task LogOrganizationUserEvent_LogsRequiredInfo(OrganizationUser orgUser, EventType eventType, DateTime date,
|
||||
Guid actingUserId, Guid providerId, string ipAddress, DeviceType deviceType, SutProvider<EventService> sutProvider)
|
||||
{
|
||||
var orgAbilities = new Dictionary<Guid, OrganizationAbility>()
|
||||
var expected = new List<IEvent>() {
|
||||
new EventMessage()
|
||||
{
|
||||
{orgUser.OrganizationId, new OrganizationAbility() { UseEvents = true, Enabled = true } }
|
||||
};
|
||||
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilitiesAsync().Returns(orgAbilities);
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||
sutProvider.GetDependency<ICurrentContext>().IpAddress.Returns(ipAddress);
|
||||
sutProvider.GetDependency<ICurrentContext>().DeviceType.Returns(deviceType);
|
||||
sutProvider.GetDependency<ICurrentContext>().ProviderIdForOrg(Arg.Any<Guid>()).Returns(providerId);
|
||||
IpAddress = ipAddress,
|
||||
DeviceType = deviceType,
|
||||
OrganizationId = orgUser.OrganizationId,
|
||||
UserId = orgUser.UserId,
|
||||
OrganizationUserId = orgUser.Id,
|
||||
ProviderId = providerId,
|
||||
Type = eventType,
|
||||
ActingUserId = actingUserId,
|
||||
Date = date
|
||||
}
|
||||
};
|
||||
|
||||
await sutProvider.Sut.LogOrganizationUserEventAsync(orgUser, eventType, date);
|
||||
await sutProvider.GetDependency<IEventWriteService>().Received(1).CreateManyAsync(Arg.Is(AssertHelper.AssertPropertyEqual<IEvent>(expected, new[] { "IdempotencyId" })));
|
||||
}
|
||||
|
||||
var expected = new List<IEvent>() {
|
||||
new EventMessage()
|
||||
{
|
||||
IpAddress = ipAddress,
|
||||
DeviceType = deviceType,
|
||||
OrganizationId = orgUser.OrganizationId,
|
||||
UserId = orgUser.UserId,
|
||||
OrganizationUserId = orgUser.Id,
|
||||
ProviderId = providerId,
|
||||
Type = eventType,
|
||||
ActingUserId = actingUserId,
|
||||
Date = date
|
||||
}
|
||||
};
|
||||
|
||||
await sutProvider.GetDependency<IEventWriteService>().Received(1).CreateManyAsync(Arg.Is(AssertHelper.AssertPropertyEqual<IEvent>(expected, new[] { "IdempotencyId" })));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task LogProviderUserEvent_LogsRequiredInfo(ProviderUser providerUser, EventType eventType, DateTime date,
|
||||
Guid actingUserId, Guid providerId, string ipAddress, DeviceType deviceType, SutProvider<EventService> sutProvider)
|
||||
[Theory, BitAutoData]
|
||||
public async Task LogProviderUserEvent_LogsRequiredInfo(ProviderUser providerUser, EventType eventType, DateTime date,
|
||||
Guid actingUserId, Guid providerId, string ipAddress, DeviceType deviceType, SutProvider<EventService> sutProvider)
|
||||
{
|
||||
var providerAbilities = new Dictionary<Guid, ProviderAbility>()
|
||||
{
|
||||
var providerAbilities = new Dictionary<Guid, ProviderAbility>()
|
||||
{providerUser.ProviderId, new ProviderAbility() { UseEvents = true, Enabled = true } }
|
||||
};
|
||||
sutProvider.GetDependency<IApplicationCacheService>().GetProviderAbilitiesAsync().Returns(providerAbilities);
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||
sutProvider.GetDependency<ICurrentContext>().IpAddress.Returns(ipAddress);
|
||||
sutProvider.GetDependency<ICurrentContext>().DeviceType.Returns(deviceType);
|
||||
sutProvider.GetDependency<ICurrentContext>().ProviderIdForOrg(Arg.Any<Guid>()).Returns(providerId);
|
||||
|
||||
await sutProvider.Sut.LogProviderUserEventAsync(providerUser, eventType, date);
|
||||
|
||||
var expected = new List<IEvent>() {
|
||||
new EventMessage()
|
||||
{
|
||||
{providerUser.ProviderId, new ProviderAbility() { UseEvents = true, Enabled = true } }
|
||||
};
|
||||
sutProvider.GetDependency<IApplicationCacheService>().GetProviderAbilitiesAsync().Returns(providerAbilities);
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||
sutProvider.GetDependency<ICurrentContext>().IpAddress.Returns(ipAddress);
|
||||
sutProvider.GetDependency<ICurrentContext>().DeviceType.Returns(deviceType);
|
||||
sutProvider.GetDependency<ICurrentContext>().ProviderIdForOrg(Arg.Any<Guid>()).Returns(providerId);
|
||||
IpAddress = ipAddress,
|
||||
DeviceType = deviceType,
|
||||
ProviderId = providerUser.ProviderId,
|
||||
UserId = providerUser.UserId,
|
||||
ProviderUserId = providerUser.Id,
|
||||
Type = eventType,
|
||||
ActingUserId = actingUserId,
|
||||
Date = date
|
||||
}
|
||||
};
|
||||
|
||||
await sutProvider.Sut.LogProviderUserEventAsync(providerUser, eventType, date);
|
||||
|
||||
var expected = new List<IEvent>() {
|
||||
new EventMessage()
|
||||
{
|
||||
IpAddress = ipAddress,
|
||||
DeviceType = deviceType,
|
||||
ProviderId = providerUser.ProviderId,
|
||||
UserId = providerUser.UserId,
|
||||
ProviderUserId = providerUser.Id,
|
||||
Type = eventType,
|
||||
ActingUserId = actingUserId,
|
||||
Date = date
|
||||
}
|
||||
};
|
||||
|
||||
await sutProvider.GetDependency<IEventWriteService>().Received(1).CreateManyAsync(Arg.Is(AssertHelper.AssertPropertyEqual<IEvent>(expected, new[] { "IdempotencyId" })));
|
||||
}
|
||||
await sutProvider.GetDependency<IEventWriteService>().Received(1).CreateManyAsync(Arg.Is(AssertHelper.AssertPropertyEqual<IEvent>(expected, new[] { "IdempotencyId" })));
|
||||
}
|
||||
}
|
||||
|
@ -10,128 +10,127 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class GroupServiceTests
|
||||
{
|
||||
public class GroupServiceTests
|
||||
[Theory, GroupOrganizationAutoData]
|
||||
public async Task SaveAsync_DefaultGroupId_CreatesGroupInRepository(Group group, Organization organization, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
[Theory, GroupOrganizationAutoData]
|
||||
public async Task SaveAsync_DefaultGroupId_CreatesGroupInRepository(Group group, Organization organization, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
group.Id = default(Guid);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
organization.UseGroups = true;
|
||||
var utcNow = DateTime.UtcNow;
|
||||
group.Id = default(Guid);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
organization.UseGroups = true;
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
await sutProvider.Sut.SaveAsync(group);
|
||||
await sutProvider.Sut.SaveAsync(group);
|
||||
|
||||
await sutProvider.GetDependency<IGroupRepository>().Received().CreateAsync(group);
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogGroupEventAsync(group, EventType.Group_Created);
|
||||
Assert.True(group.CreationDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
Assert.True(group.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
await sutProvider.GetDependency<IGroupRepository>().Received().CreateAsync(group);
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogGroupEventAsync(group, EventType.Group_Created);
|
||||
Assert.True(group.CreationDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
Assert.True(group.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Theory, GroupOrganizationAutoData]
|
||||
public async Task SaveAsync_DefaultGroupIdAndCollections_CreatesGroupInRepository(Group group, Organization organization, List<SelectionReadOnly> collections, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
group.Id = default(Guid);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
organization.UseGroups = true;
|
||||
var utcNow = DateTime.UtcNow;
|
||||
[Theory, GroupOrganizationAutoData]
|
||||
public async Task SaveAsync_DefaultGroupIdAndCollections_CreatesGroupInRepository(Group group, Organization organization, List<SelectionReadOnly> collections, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
group.Id = default(Guid);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
organization.UseGroups = true;
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
await sutProvider.Sut.SaveAsync(group, collections);
|
||||
await sutProvider.Sut.SaveAsync(group, collections);
|
||||
|
||||
await sutProvider.GetDependency<IGroupRepository>().Received().CreateAsync(group, collections);
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogGroupEventAsync(group, EventType.Group_Created);
|
||||
Assert.True(group.CreationDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
Assert.True(group.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
await sutProvider.GetDependency<IGroupRepository>().Received().CreateAsync(group, collections);
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogGroupEventAsync(group, EventType.Group_Created);
|
||||
Assert.True(group.CreationDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
Assert.True(group.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Theory, GroupOrganizationAutoData]
|
||||
public async Task SaveAsync_NonDefaultGroupId_ReplaceGroupInRepository(Group group, Organization organization, List<SelectionReadOnly> collections, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
organization.UseGroups = true;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
[Theory, GroupOrganizationAutoData]
|
||||
public async Task SaveAsync_NonDefaultGroupId_ReplaceGroupInRepository(Group group, Organization organization, List<SelectionReadOnly> collections, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
organization.UseGroups = true;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
|
||||
await sutProvider.Sut.SaveAsync(group, collections);
|
||||
await sutProvider.Sut.SaveAsync(group, collections);
|
||||
|
||||
await sutProvider.GetDependency<IGroupRepository>().Received().ReplaceAsync(group, collections);
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogGroupEventAsync(group, EventType.Group_Updated);
|
||||
Assert.True(group.RevisionDate - DateTime.UtcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
await sutProvider.GetDependency<IGroupRepository>().Received().ReplaceAsync(group, collections);
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogGroupEventAsync(group, EventType.Group_Updated);
|
||||
Assert.True(group.RevisionDate - DateTime.UtcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_NonExistingOrganizationId_ThrowsBadRequest(Group group, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(group));
|
||||
Assert.Contains("Organization not found", exception.Message);
|
||||
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().CreateAsync(default);
|
||||
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
|
||||
await sutProvider.GetDependency<IEventService>().DidNotReceiveWithAnyArgs().LogGroupEventAsync(default, default, default);
|
||||
}
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_NonExistingOrganizationId_ThrowsBadRequest(Group group, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(group));
|
||||
Assert.Contains("Organization not found", exception.Message);
|
||||
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().CreateAsync(default);
|
||||
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
|
||||
await sutProvider.GetDependency<IEventService>().DidNotReceiveWithAnyArgs().LogGroupEventAsync(default, default, default);
|
||||
}
|
||||
|
||||
[Theory, GroupOrganizationNotUseGroupsAutoData]
|
||||
public async Task SaveAsync_OrganizationDoesNotUseGroups_ThrowsBadRequest(Group group, Organization organization, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
[Theory, GroupOrganizationNotUseGroupsAutoData]
|
||||
public async Task SaveAsync_OrganizationDoesNotUseGroups_ThrowsBadRequest(Group group, Organization organization, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(group));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(group));
|
||||
|
||||
Assert.Contains("This organization cannot use groups", exception.Message);
|
||||
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().CreateAsync(default);
|
||||
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
|
||||
await sutProvider.GetDependency<IEventService>().DidNotReceiveWithAnyArgs().LogGroupEventAsync(default, default, default);
|
||||
}
|
||||
Assert.Contains("This organization cannot use groups", exception.Message);
|
||||
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().CreateAsync(default);
|
||||
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().ReplaceAsync(default);
|
||||
await sutProvider.GetDependency<IEventService>().DidNotReceiveWithAnyArgs().LogGroupEventAsync(default, default, default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task DeleteAsync_ValidData_DeletesGroup(Group group, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
await sutProvider.Sut.DeleteAsync(group);
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task DeleteAsync_ValidData_DeletesGroup(Group group, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
await sutProvider.Sut.DeleteAsync(group);
|
||||
|
||||
await sutProvider.GetDependency<IGroupRepository>().Received().DeleteAsync(group);
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogGroupEventAsync(group, EventType.Group_Deleted);
|
||||
}
|
||||
await sutProvider.GetDependency<IGroupRepository>().Received().DeleteAsync(group);
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogGroupEventAsync(group, EventType.Group_Deleted);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task DeleteUserAsync_ValidData_DeletesUserInGroupRepository(Group group, Organization organization, OrganizationUser organizationUser, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
group.OrganizationId = organization.Id;
|
||||
organization.UseGroups = true;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(organizationUser.Id)
|
||||
.Returns(organizationUser);
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task DeleteUserAsync_ValidData_DeletesUserInGroupRepository(Group group, Organization organization, OrganizationUser organizationUser, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
group.OrganizationId = organization.Id;
|
||||
organization.UseGroups = true;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(organizationUser.Id)
|
||||
.Returns(organizationUser);
|
||||
|
||||
await sutProvider.Sut.DeleteUserAsync(group, organizationUser.Id);
|
||||
await sutProvider.Sut.DeleteUserAsync(group, organizationUser.Id);
|
||||
|
||||
await sutProvider.GetDependency<IGroupRepository>().Received().DeleteUserAsync(group.Id, organizationUser.Id);
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_UpdatedGroups);
|
||||
}
|
||||
await sutProvider.GetDependency<IGroupRepository>().Received().DeleteUserAsync(group.Id, organizationUser.Id);
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_UpdatedGroups);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task DeleteUserAsync_InvalidUser_ThrowsNotFound(Group group, Organization organization, OrganizationUser organizationUser, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
group.OrganizationId = organization.Id;
|
||||
organization.UseGroups = true;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
// organizationUser.OrganizationId = organization.Id;
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(organizationUser.Id)
|
||||
.Returns(organizationUser);
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task DeleteUserAsync_InvalidUser_ThrowsNotFound(Group group, Organization organization, OrganizationUser organizationUser, SutProvider<GroupService> sutProvider)
|
||||
{
|
||||
group.OrganizationId = organization.Id;
|
||||
organization.UseGroups = true;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
// organizationUser.OrganizationId = organization.Id;
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(organizationUser.Id)
|
||||
.Returns(organizationUser);
|
||||
|
||||
// user not in organization
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.DeleteUserAsync(group, organizationUser.Id));
|
||||
// invalid user
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.DeleteUserAsync(group, Guid.NewGuid()));
|
||||
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs()
|
||||
.DeleteUserAsync(default, default);
|
||||
await sutProvider.GetDependency<IEventService>().DidNotReceiveWithAnyArgs()
|
||||
.LogOrganizationUserEventAsync(default, default);
|
||||
}
|
||||
// user not in organization
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.DeleteUserAsync(group, organizationUser.Id));
|
||||
// invalid user
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.DeleteUserAsync(group, Guid.NewGuid()));
|
||||
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs()
|
||||
.DeleteUserAsync(default, default);
|
||||
await sutProvider.GetDependency<IEventService>().DidNotReceiveWithAnyArgs()
|
||||
.LogOrganizationUserEventAsync(default, default);
|
||||
}
|
||||
}
|
||||
|
@ -8,169 +8,168 @@ using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class HandlebarsMailServiceTests
|
||||
{
|
||||
public class HandlebarsMailServiceTests
|
||||
private readonly HandlebarsMailService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IMailDeliveryService _mailDeliveryService;
|
||||
private readonly IMailEnqueuingService _mailEnqueuingService;
|
||||
|
||||
public HandlebarsMailServiceTests()
|
||||
{
|
||||
private readonly HandlebarsMailService _sut;
|
||||
_globalSettings = new GlobalSettings();
|
||||
_mailDeliveryService = Substitute.For<IMailDeliveryService>();
|
||||
_mailEnqueuingService = Substitute.For<IMailEnqueuingService>();
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IMailDeliveryService _mailDeliveryService;
|
||||
private readonly IMailEnqueuingService _mailEnqueuingService;
|
||||
_sut = new HandlebarsMailService(
|
||||
_globalSettings,
|
||||
_mailDeliveryService,
|
||||
_mailEnqueuingService
|
||||
);
|
||||
}
|
||||
|
||||
public HandlebarsMailServiceTests()
|
||||
[Fact(Skip = "For local development")]
|
||||
public async Task SendAllEmails()
|
||||
{
|
||||
// This test is only opt in and is more for development purposes.
|
||||
// This will send all emails to the test email address so that they can be viewed.
|
||||
var namedParameters = new Dictionary<(string, Type), object>
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
_mailDeliveryService = Substitute.For<IMailDeliveryService>();
|
||||
_mailEnqueuingService = Substitute.For<IMailEnqueuingService>();
|
||||
// TODO: Swith to use env variable
|
||||
{ ("email", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("user", typeof(User)), new User
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Email = "test@bitwarden.com",
|
||||
}},
|
||||
{ ("userId", typeof(Guid)), Guid.NewGuid() },
|
||||
{ ("token", typeof(string)), "test_token" },
|
||||
{ ("fromEmail", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("toEmail", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("newEmailAddress", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("hint", typeof(string)), "Test Hint" },
|
||||
{ ("organizationName", typeof(string)), "Test Organization Name" },
|
||||
{ ("orgUser", typeof(OrganizationUser)), new OrganizationUser
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Email = "test@bitwarden.com",
|
||||
OrganizationId = Guid.NewGuid(),
|
||||
|
||||
_sut = new HandlebarsMailService(
|
||||
_globalSettings,
|
||||
_mailDeliveryService,
|
||||
_mailEnqueuingService
|
||||
);
|
||||
}},
|
||||
{ ("token", typeof(ExpiringToken)), new ExpiringToken("test_token", DateTime.UtcNow.AddDays(1))},
|
||||
{ ("organization", typeof(Organization)), new Organization
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = "Test Organization Name",
|
||||
Seats = 5
|
||||
}},
|
||||
{ ("initialSeatCount", typeof(int)), 5},
|
||||
{ ("ownerEmails", typeof(IEnumerable<string>)), new [] { "test@bitwarden.com" }},
|
||||
{ ("maxSeatCount", typeof(int)), 5 },
|
||||
{ ("userIdentifier", typeof(string)), "test_user" },
|
||||
{ ("adminEmails", typeof(IEnumerable<string>)), new [] { "test@bitwarden.com" }},
|
||||
{ ("returnUrl", typeof(string)), "https://bitwarden.com/" },
|
||||
{ ("amount", typeof(decimal)), 1.00M },
|
||||
{ ("dueDate", typeof(DateTime)), DateTime.UtcNow.AddDays(1) },
|
||||
{ ("items", typeof(List<string>)), new List<string> { "test@bitwarden.com" }},
|
||||
{ ("mentionInvoices", typeof(bool)), true },
|
||||
{ ("emails", typeof(IEnumerable<string>)), new [] { "test@bitwarden.com" }},
|
||||
{ ("deviceType", typeof(string)), "Mobile" },
|
||||
{ ("timestamp", typeof(DateTime)), DateTime.UtcNow.AddDays(1)},
|
||||
{ ("ip", typeof(string)), "127.0.0.1" },
|
||||
{ ("emergencyAccess", typeof(EmergencyAccess)), new EmergencyAccess
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Email = "test@bitwarden.com",
|
||||
}},
|
||||
{ ("granteeEmail", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("grantorName", typeof(string)), "Test User" },
|
||||
{ ("initiatingName", typeof(string)), "Test" },
|
||||
{ ("approvingName", typeof(string)), "Test Name" },
|
||||
{ ("rejectingName", typeof(string)), "Test Name" },
|
||||
{ ("provider", typeof(Provider)), new Provider
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
}},
|
||||
{ ("name", typeof(string)), "Test Name" },
|
||||
{ ("ea", typeof(EmergencyAccess)), new EmergencyAccess
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Email = "test@bitwarden.com",
|
||||
}},
|
||||
{ ("userName", typeof(string)), "testUser" },
|
||||
{ ("orgName", typeof(string)), "Test Org Name" },
|
||||
{ ("providerName", typeof(string)), "testProvider" },
|
||||
{ ("providerUser", typeof(ProviderUser)), new ProviderUser
|
||||
{
|
||||
ProviderId = Guid.NewGuid(),
|
||||
Id = Guid.NewGuid(),
|
||||
}},
|
||||
{ ("familyUserEmail", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("sponsorEmail", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("familyOrgName", typeof(string)), "Test Org Name" },
|
||||
// Swap existingAccount to true or false to generate different versions of the SendFamiliesForEnterpriseOfferEmailAsync emails.
|
||||
{ ("existingAccount", typeof(bool)), false },
|
||||
{ ("sponsorshipEndDate", typeof(DateTime)), DateTime.UtcNow.AddDays(1)},
|
||||
{ ("sponsorOrgName", typeof(string)), "Sponsor Test Org Name" },
|
||||
{ ("expirationDate", typeof(DateTime)), DateTime.Now.AddDays(3) },
|
||||
{ ("utcNow", typeof(DateTime)), DateTime.UtcNow },
|
||||
};
|
||||
|
||||
var globalSettings = new GlobalSettings
|
||||
{
|
||||
Mail = new GlobalSettings.MailSettings
|
||||
{
|
||||
Smtp = new GlobalSettings.MailSettings.SmtpSettings
|
||||
{
|
||||
Host = "localhost",
|
||||
TrustServer = true,
|
||||
Port = 10250,
|
||||
},
|
||||
ReplyToEmail = "noreply@bitwarden.com",
|
||||
},
|
||||
SiteName = "Bitwarden",
|
||||
};
|
||||
|
||||
var mailDeliveryService = new MailKitSmtpMailDeliveryService(globalSettings, Substitute.For<ILogger<MailKitSmtpMailDeliveryService>>());
|
||||
|
||||
var handlebarsService = new HandlebarsMailService(globalSettings, mailDeliveryService, new BlockingMailEnqueuingService());
|
||||
|
||||
var sendMethods = typeof(IMailService).GetMethods(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(m => m.Name.StartsWith("Send") && m.Name != "SendEnqueuedMailMessageAsync");
|
||||
|
||||
foreach (var sendMethod in sendMethods)
|
||||
{
|
||||
await InvokeMethod(sendMethod);
|
||||
}
|
||||
|
||||
[Fact(Skip = "For local development")]
|
||||
public async Task SendAllEmails()
|
||||
async Task InvokeMethod(MethodInfo method)
|
||||
{
|
||||
// This test is only opt in and is more for development purposes.
|
||||
// This will send all emails to the test email address so that they can be viewed.
|
||||
var namedParameters = new Dictionary<(string, Type), object>
|
||||
var parameters = method.GetParameters();
|
||||
var args = new object[parameters.Length];
|
||||
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
// TODO: Swith to use env variable
|
||||
{ ("email", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("user", typeof(User)), new User
|
||||
if (!namedParameters.TryGetValue((parameters[i].Name, parameters[i].ParameterType), out var value))
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Email = "test@bitwarden.com",
|
||||
}},
|
||||
{ ("userId", typeof(Guid)), Guid.NewGuid() },
|
||||
{ ("token", typeof(string)), "test_token" },
|
||||
{ ("fromEmail", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("toEmail", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("newEmailAddress", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("hint", typeof(string)), "Test Hint" },
|
||||
{ ("organizationName", typeof(string)), "Test Organization Name" },
|
||||
{ ("orgUser", typeof(OrganizationUser)), new OrganizationUser
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Email = "test@bitwarden.com",
|
||||
OrganizationId = Guid.NewGuid(),
|
||||
|
||||
}},
|
||||
{ ("token", typeof(ExpiringToken)), new ExpiringToken("test_token", DateTime.UtcNow.AddDays(1))},
|
||||
{ ("organization", typeof(Organization)), new Organization
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = "Test Organization Name",
|
||||
Seats = 5
|
||||
}},
|
||||
{ ("initialSeatCount", typeof(int)), 5},
|
||||
{ ("ownerEmails", typeof(IEnumerable<string>)), new [] { "test@bitwarden.com" }},
|
||||
{ ("maxSeatCount", typeof(int)), 5 },
|
||||
{ ("userIdentifier", typeof(string)), "test_user" },
|
||||
{ ("adminEmails", typeof(IEnumerable<string>)), new [] { "test@bitwarden.com" }},
|
||||
{ ("returnUrl", typeof(string)), "https://bitwarden.com/" },
|
||||
{ ("amount", typeof(decimal)), 1.00M },
|
||||
{ ("dueDate", typeof(DateTime)), DateTime.UtcNow.AddDays(1) },
|
||||
{ ("items", typeof(List<string>)), new List<string> { "test@bitwarden.com" }},
|
||||
{ ("mentionInvoices", typeof(bool)), true },
|
||||
{ ("emails", typeof(IEnumerable<string>)), new [] { "test@bitwarden.com" }},
|
||||
{ ("deviceType", typeof(string)), "Mobile" },
|
||||
{ ("timestamp", typeof(DateTime)), DateTime.UtcNow.AddDays(1)},
|
||||
{ ("ip", typeof(string)), "127.0.0.1" },
|
||||
{ ("emergencyAccess", typeof(EmergencyAccess)), new EmergencyAccess
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Email = "test@bitwarden.com",
|
||||
}},
|
||||
{ ("granteeEmail", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("grantorName", typeof(string)), "Test User" },
|
||||
{ ("initiatingName", typeof(string)), "Test" },
|
||||
{ ("approvingName", typeof(string)), "Test Name" },
|
||||
{ ("rejectingName", typeof(string)), "Test Name" },
|
||||
{ ("provider", typeof(Provider)), new Provider
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
}},
|
||||
{ ("name", typeof(string)), "Test Name" },
|
||||
{ ("ea", typeof(EmergencyAccess)), new EmergencyAccess
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Email = "test@bitwarden.com",
|
||||
}},
|
||||
{ ("userName", typeof(string)), "testUser" },
|
||||
{ ("orgName", typeof(string)), "Test Org Name" },
|
||||
{ ("providerName", typeof(string)), "testProvider" },
|
||||
{ ("providerUser", typeof(ProviderUser)), new ProviderUser
|
||||
{
|
||||
ProviderId = Guid.NewGuid(),
|
||||
Id = Guid.NewGuid(),
|
||||
}},
|
||||
{ ("familyUserEmail", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("sponsorEmail", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("familyOrgName", typeof(string)), "Test Org Name" },
|
||||
// Swap existingAccount to true or false to generate different versions of the SendFamiliesForEnterpriseOfferEmailAsync emails.
|
||||
{ ("existingAccount", typeof(bool)), false },
|
||||
{ ("sponsorshipEndDate", typeof(DateTime)), DateTime.UtcNow.AddDays(1)},
|
||||
{ ("sponsorOrgName", typeof(string)), "Sponsor Test Org Name" },
|
||||
{ ("expirationDate", typeof(DateTime)), DateTime.Now.AddDays(3) },
|
||||
{ ("utcNow", typeof(DateTime)), DateTime.UtcNow },
|
||||
};
|
||||
|
||||
var globalSettings = new GlobalSettings
|
||||
{
|
||||
Mail = new GlobalSettings.MailSettings
|
||||
{
|
||||
Smtp = new GlobalSettings.MailSettings.SmtpSettings
|
||||
{
|
||||
Host = "localhost",
|
||||
TrustServer = true,
|
||||
Port = 10250,
|
||||
},
|
||||
ReplyToEmail = "noreply@bitwarden.com",
|
||||
},
|
||||
SiteName = "Bitwarden",
|
||||
};
|
||||
|
||||
var mailDeliveryService = new MailKitSmtpMailDeliveryService(globalSettings, Substitute.For<ILogger<MailKitSmtpMailDeliveryService>>());
|
||||
|
||||
var handlebarsService = new HandlebarsMailService(globalSettings, mailDeliveryService, new BlockingMailEnqueuingService());
|
||||
|
||||
var sendMethods = typeof(IMailService).GetMethods(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(m => m.Name.StartsWith("Send") && m.Name != "SendEnqueuedMailMessageAsync");
|
||||
|
||||
foreach (var sendMethod in sendMethods)
|
||||
{
|
||||
await InvokeMethod(sendMethod);
|
||||
}
|
||||
|
||||
async Task InvokeMethod(MethodInfo method)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
var args = new object[parameters.Length];
|
||||
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
if (!namedParameters.TryGetValue((parameters[i].Name, parameters[i].ParameterType), out var value))
|
||||
{
|
||||
throw new InvalidOperationException($"Couldn't find a parameter for name '{parameters[i].Name}' and type '{parameters[i].ParameterType.FullName}'");
|
||||
}
|
||||
|
||||
args[i] = value;
|
||||
throw new InvalidOperationException($"Couldn't find a parameter for name '{parameters[i].Name}' and type '{parameters[i].ParameterType.FullName}'");
|
||||
}
|
||||
|
||||
await (Task)method.Invoke(handlebarsService, args);
|
||||
args[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove this test when we add actual tests. It only proves that
|
||||
// we've properly constructed the system under test.
|
||||
[Fact]
|
||||
public void ServiceExists()
|
||||
{
|
||||
Assert.NotNull(_sut);
|
||||
await (Task)method.Invoke(handlebarsService, args);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove this test when we add actual tests. It only proves that
|
||||
// we've properly constructed the system under test.
|
||||
[Fact]
|
||||
public void ServiceExists()
|
||||
{
|
||||
Assert.NotNull(_sut);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user