mirror of
https://github.com/bitwarden/server
synced 2026-01-05 01:53:17 +00:00
Revert filescoped (#2227)
* Revert "Add git blame entry (#2226)" This reverts commit239286737d. * Revert "Turn on file scoped namespaces (#2225)" This reverts commit34fb4cca2a.
This commit is contained in:
@@ -8,79 +8,80 @@ using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class AmazonSesMailDeliveryServiceTests : IDisposable
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly AmazonSesMailDeliveryService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IWebHostEnvironment _hostingEnvironment;
|
||||
private readonly ILogger<AmazonSesMailDeliveryService> _logger;
|
||||
private readonly IAmazonSimpleEmailService _amazonSimpleEmailService;
|
||||
|
||||
public AmazonSesMailDeliveryServiceTests()
|
||||
public class AmazonSesMailDeliveryServiceTests : IDisposable
|
||||
{
|
||||
_globalSettings = new GlobalSettings
|
||||
private readonly AmazonSesMailDeliveryService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IWebHostEnvironment _hostingEnvironment;
|
||||
private readonly ILogger<AmazonSesMailDeliveryService> _logger;
|
||||
private readonly IAmazonSimpleEmailService _amazonSimpleEmailService;
|
||||
|
||||
public AmazonSesMailDeliveryServiceTests()
|
||||
{
|
||||
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 =>
|
||||
_globalSettings = new GlobalSettings
|
||||
{
|
||||
Assert.False(string.IsNullOrEmpty(request.Source));
|
||||
Amazon =
|
||||
{
|
||||
AccessKeyId = "AccessKeyId-AmazonSesMailDeliveryServiceTests",
|
||||
AccessKeySecret = "AccessKeySecret-AmazonSesMailDeliveryServiceTests",
|
||||
Region = "Region-AmazonSesMailDeliveryServiceTests"
|
||||
}
|
||||
};
|
||||
|
||||
Assert.Single(request.Destination.ToAddresses);
|
||||
Assert.Equal(mailMessage.ToEmails.First(), request.Destination.ToAddresses.First());
|
||||
_hostingEnvironment = Substitute.For<IWebHostEnvironment>();
|
||||
_logger = Substitute.For<ILogger<AmazonSesMailDeliveryService>>();
|
||||
_amazonSimpleEmailService = Substitute.For<IAmazonSimpleEmailService>();
|
||||
|
||||
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);
|
||||
_sut = new AmazonSesMailDeliveryService(
|
||||
_globalSettings,
|
||||
_hostingEnvironment,
|
||||
_logger,
|
||||
_amazonSimpleEmailService
|
||||
);
|
||||
}
|
||||
|
||||
Assert.Single(request.Destination.BccAddresses);
|
||||
Assert.Equal(mailMessage.BccEmails.First(), request.Destination.BccAddresses.First());
|
||||
public void Dispose()
|
||||
{
|
||||
_sut?.Dispose();
|
||||
}
|
||||
|
||||
Assert.Contains(request.Tags, x => x.Name == "Environment");
|
||||
Assert.Contains(request.Tags, x => x.Name == "Sender");
|
||||
Assert.Contains(request.Tags, x => x.Name == "Category");
|
||||
}));
|
||||
[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");
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,73 +4,74 @@ using Bit.Core.Settings;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class AmazonSqsBlockIpServiceTests : IDisposable
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly AmazonSqsBlockIpService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IAmazonSQS _amazonSqs;
|
||||
|
||||
public AmazonSqsBlockIpServiceTests()
|
||||
public class AmazonSqsBlockIpServiceTests : IDisposable
|
||||
{
|
||||
_globalSettings = new GlobalSettings
|
||||
private readonly AmazonSqsBlockIpService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IAmazonSQS _amazonSqs;
|
||||
|
||||
public AmazonSqsBlockIpServiceTests()
|
||||
{
|
||||
Amazon =
|
||||
_globalSettings = new GlobalSettings
|
||||
{
|
||||
AccessKeyId = "AccessKeyId-AmazonSesMailDeliveryServiceTests",
|
||||
AccessKeySecret = "AccessKeySecret-AmazonSesMailDeliveryServiceTests",
|
||||
Region = "Region-AmazonSesMailDeliveryServiceTests"
|
||||
}
|
||||
};
|
||||
Amazon =
|
||||
{
|
||||
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,35 +6,36 @@ using NSubstitute;
|
||||
using NSubstitute.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class AppleIapServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetReceiptStatusAsync_MoreThanFourAttempts_Throws(SutProvider<AppleIapService> sutProvider)
|
||||
[SutProviderCustomize]
|
||||
public class AppleIapServiceTests
|
||||
{
|
||||
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)
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetReceiptStatusAsync_MoreThanFourAttempts_Throws(SutProvider<AppleIapService> sutProvider)
|
||||
{
|
||||
if (call.GetMethodInfo().Name != "Log")
|
||||
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)
|
||||
{
|
||||
return false;
|
||||
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");
|
||||
}
|
||||
|
||||
var args = call.GetArguments();
|
||||
var logLevel = (LogLevel)args[0];
|
||||
var exception = (Exception)args[3];
|
||||
|
||||
return logLevel == LogLevel.Warning && exception.Message.Contains("null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,28 +4,29 @@ using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class AzureAttachmentStorageServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly AzureAttachmentStorageService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ILogger<AzureAttachmentStorageService> _logger;
|
||||
|
||||
public AzureAttachmentStorageServiceTests()
|
||||
public class AzureAttachmentStorageServiceTests
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
_logger = Substitute.For<ILogger<AzureAttachmentStorageService>>();
|
||||
private readonly AzureAttachmentStorageService _sut;
|
||||
|
||||
_sut = new AzureAttachmentStorageService(_globalSettings, _logger);
|
||||
}
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ILogger<AzureAttachmentStorageService> _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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,26 +2,27 @@
|
||||
using Bit.Core.Settings;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class AzureQueueBlockIpServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly AzureQueueBlockIpService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
public AzureQueueBlockIpServiceTests()
|
||||
public class AzureQueueBlockIpServiceTests
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
private readonly AzureQueueBlockIpService _sut;
|
||||
|
||||
_sut = new AzureQueueBlockIpService(_globalSettings);
|
||||
}
|
||||
private readonly GlobalSettings _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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,30 +4,31 @@ using Bit.Core.Settings;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class AzureQueueEventWriteServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly AzureQueueEventWriteService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IEventRepository _eventRepository;
|
||||
|
||||
public AzureQueueEventWriteServiceTests()
|
||||
public class AzureQueueEventWriteServiceTests
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
_eventRepository = Substitute.For<IEventRepository>();
|
||||
private readonly AzureQueueEventWriteService _sut;
|
||||
|
||||
_sut = new AzureQueueEventWriteService(
|
||||
_globalSettings
|
||||
);
|
||||
}
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IEventRepository _eventRepository;
|
||||
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,31 +4,32 @@ using Microsoft.AspNetCore.Http;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class AzureQueuePushNotificationServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly AzureQueuePushNotificationService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public AzureQueuePushNotificationServiceTests()
|
||||
public class AzureQueuePushNotificationServiceTests
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
_httpContextAccessor = Substitute.For<IHttpContextAccessor>();
|
||||
private readonly AzureQueuePushNotificationService _sut;
|
||||
|
||||
_sut = new AzureQueuePushNotificationService(
|
||||
_globalSettings,
|
||||
_httpContextAccessor
|
||||
);
|
||||
}
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,208 +9,209 @@ using Core.Models.Data;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class CipherServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
[Theory, UserCipherAutoData]
|
||||
public async Task SaveAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider, Cipher cipher)
|
||||
public class CipherServiceTests
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
[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]
|
||||
public async Task SaveAsync_WrongRevisionDate_Throws(SutProvider<CipherService> sutProvider, Cipher cipher)
|
||||
{
|
||||
cipher.RevisionDate = previousRevisionDate;
|
||||
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 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)
|
||||
[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);
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
[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.Equal(revisionDate, cipher.RevisionDate);
|
||||
Assert.NotEqual(initialRevisionDate, 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
|
||||
[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)
|
||||
{
|
||||
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
|
||||
var previousRevisionDate = DateTime.UtcNow;
|
||||
foreach (var cipher in ciphers)
|
||||
{
|
||||
PlanType = Enums.PlanType.EnterpriseAnnually,
|
||||
MaxStorageGb = 100
|
||||
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
|
||||
});
|
||||
ciphers.FirstOrDefault().Attachments =
|
||||
"{\"attachment1\":{\"Size\":\"250\",\"FileName\":\"superCoolFile\","
|
||||
+ "\"Key\":\"superCoolFile\",\"ContainerName\":\"testContainer\",\"Validated\":false}}";
|
||||
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));
|
||||
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()));
|
||||
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,160 +10,161 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class CollectionServiceTest
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
[Theory, CollectionAutoData]
|
||||
public async Task SaveAsync_DefaultId_CreatesCollectionInTheRepository(Collection collection, Organization organization, SutProvider<CollectionService> sutProvider)
|
||||
public class CollectionServiceTest
|
||||
{
|
||||
collection.Id = default;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
[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;
|
||||
|
||||
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,32 +5,33 @@ using Bit.Core.Services;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class DeviceServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
[Fact]
|
||||
public async Task DeviceSaveShouldUpdateRevisionDateAndPushRegistration()
|
||||
public class DeviceServiceTests
|
||||
{
|
||||
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
|
||||
[Fact]
|
||||
public async Task DeviceSaveShouldUpdateRevisionDateAndPushRegistration()
|
||||
{
|
||||
Id = id,
|
||||
Name = "test device",
|
||||
Type = DeviceType.Android,
|
||||
UserId = userId,
|
||||
PushToken = "testtoken",
|
||||
Identifier = "testid"
|
||||
};
|
||||
await deviceService.SaveAsync(device);
|
||||
var deviceRepo = Substitute.For<IDeviceRepository>();
|
||||
var pushRepo = Substitute.For<IPushRegistrationService>();
|
||||
var deviceService = new DeviceService(deviceRepo, pushRepo);
|
||||
|
||||
Assert.True(device.RevisionDate - DateTime.UtcNow < TimeSpan.FromSeconds(1));
|
||||
await pushRepo.Received().CreateOrUpdateRegistrationAsync("testtoken", id.ToString(),
|
||||
userId.ToString(), "testid", DeviceType.Android);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,162 +9,163 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class EmergencyAccessServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_PremiumCannotUpdate(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User savingUser)
|
||||
public class EmergencyAccessServiceTests
|
||||
{
|
||||
savingUser.Premium = false;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_PremiumCannotUpdate(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User savingUser)
|
||||
{
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
GrantorId = savingUser.Id,
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(savingUser.Id).Returns(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);
|
||||
}
|
||||
|
||||
[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
|
||||
{
|
||||
Status = Enums.EmergencyAccessStatusType.Accepted,
|
||||
GrantorId = confirmingUser.Id,
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(confirmingUser.Id).Returns(confirmingUser);
|
||||
sutProvider.GetDependency<IEmergencyAccessRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(emergencyAccess);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.ConfirmUserAsync(new Guid(), key, confirmingUser.Id));
|
||||
|
||||
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
|
||||
{
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
GrantorId = savingUser.Id,
|
||||
};
|
||||
|
||||
var userService = sutProvider.GetDependency<IUserService>();
|
||||
userService.GetUserByIdAsync(savingUser.Id).Returns(savingUser);
|
||||
userService.CanAccessPremium(savingUser).Returns(true);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task InitiateAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User initiatingUser, User grantor)
|
||||
{
|
||||
grantor.UsesKeyConnector = true;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
Status = Enums.EmergencyAccessStatusType.Confirmed,
|
||||
GranteeId = initiatingUser.Id,
|
||||
GrantorId = grantor.Id,
|
||||
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.InitiateAsync(new Guid(), initiatingUser));
|
||||
|
||||
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 TakeoverAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User requestingUser, User grantor)
|
||||
{
|
||||
grantor.UsesKeyConnector = true;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
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)
|
||||
{
|
||||
grantor.UsesKeyConnector = true;
|
||||
grantor.UnknownDeviceVerificationEnabled = true;
|
||||
grantor.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
{
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
savingUser.Premium = false;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
MetaData = new Dictionary<string, object> { ["Email"] = "asdfasf" },
|
||||
Enabled = true
|
||||
}
|
||||
});
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
GrantorId = savingUser.Id,
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(savingUser.Id).Returns(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);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task InviteAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User invitingUser, string email, int waitTime)
|
||||
{
|
||||
GrantorId = grantor.Id,
|
||||
GranteeId = requestingUser.Id,
|
||||
Status = Enums.EmergencyAccessStatusType.RecoveryApproved,
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
};
|
||||
invitingUser.UsesKeyConnector = true;
|
||||
sutProvider.GetDependency<IUserService>().CanAccessPremium(invitingUser).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.InviteAsync(invitingUser, email, Enums.EmergencyAccessType.Takeover, waitTime));
|
||||
|
||||
await sutProvider.Sut.PasswordAsync(Guid.NewGuid(), requestingUser, "blablahash", "blablakey");
|
||||
Assert.Contains("You cannot use Emergency Access Takeover because you are using Key Connector", exception.Message);
|
||||
await sutProvider.GetDependency<IEmergencyAccessRepository>().DidNotReceiveWithAnyArgs().CreateAsync(default);
|
||||
}
|
||||
|
||||
Assert.False(grantor.UnknownDeviceVerificationEnabled);
|
||||
Assert.Empty(grantor.GetTwoFactorProviders());
|
||||
await sutProvider.GetDependency<IUserRepository>().Received().ReplaceAsync(grantor);
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task ConfirmUserAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User confirmingUser, string key)
|
||||
{
|
||||
confirmingUser.UsesKeyConnector = true;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
Status = Enums.EmergencyAccessStatusType.Accepted,
|
||||
GrantorId = confirmingUser.Id,
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(confirmingUser.Id).Returns(confirmingUser);
|
||||
sutProvider.GetDependency<IEmergencyAccessRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(emergencyAccess);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.ConfirmUserAsync(new Guid(), key, confirmingUser.Id));
|
||||
|
||||
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
|
||||
{
|
||||
Type = Enums.EmergencyAccessType.Takeover,
|
||||
GrantorId = savingUser.Id,
|
||||
};
|
||||
|
||||
var userService = sutProvider.GetDependency<IUserService>();
|
||||
userService.GetUserByIdAsync(savingUser.Id).Returns(savingUser);
|
||||
userService.CanAccessPremium(savingUser).Returns(true);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task InitiateAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User initiatingUser, User grantor)
|
||||
{
|
||||
grantor.UsesKeyConnector = true;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
Status = Enums.EmergencyAccessStatusType.Confirmed,
|
||||
GranteeId = initiatingUser.Id,
|
||||
GrantorId = grantor.Id,
|
||||
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.InitiateAsync(new Guid(), initiatingUser));
|
||||
|
||||
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 TakeoverAsync_UserWithKeyConnectorCannotUseTakeover(
|
||||
SutProvider<EmergencyAccessService> sutProvider, User requestingUser, User grantor)
|
||||
{
|
||||
grantor.UsesKeyConnector = true;
|
||||
var emergencyAccess = new EmergencyAccess
|
||||
{
|
||||
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)
|
||||
{
|
||||
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,
|
||||
};
|
||||
|
||||
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");
|
||||
|
||||
Assert.False(grantor.UnknownDeviceVerificationEnabled);
|
||||
Assert.Empty(grantor.GetTwoFactorProviders());
|
||||
await sutProvider.GetDependency<IUserRepository>().Received().ReplaceAsync(grantor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,98 +11,99 @@ using Bit.Test.Common.Helpers;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class EventServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
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)
|
||||
[SutProviderCustomize]
|
||||
public class EventServiceTests
|
||||
{
|
||||
organization.Enabled = true;
|
||||
organization.UseEvents = true;
|
||||
public static IEnumerable<object[]> InstallationIdTestCases => TestCaseHelper.GetCombinationsOfMultipleLists(
|
||||
new object[] { Guid.NewGuid(), null },
|
||||
Enum.GetValues<EventType>().Select(e => (object)e)
|
||||
).Select(p => p.ToArray());
|
||||
|
||||
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>()
|
||||
[Theory]
|
||||
[BitMemberAutoData(nameof(InstallationIdTestCases))]
|
||||
public async Task LogOrganizationEvent_ProvidesInstallationId(Guid? installationId, EventType eventType,
|
||||
Organization organization, SutProvider<EventService> sutProvider)
|
||||
{
|
||||
{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);
|
||||
organization.Enabled = true;
|
||||
organization.UseEvents = true;
|
||||
|
||||
await sutProvider.Sut.LogOrganizationUserEventAsync(orgUser, eventType, date);
|
||||
sutProvider.GetDependency<ICurrentContext>().InstallationId.Returns(installationId);
|
||||
|
||||
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.Sut.LogOrganizationEventAsync(organization, eventType);
|
||||
|
||||
await sutProvider.GetDependency<IEventWriteService>().Received(1).CreateManyAsync(Arg.Is(AssertHelper.AssertPropertyEqual<IEvent>(expected, new[] { "IdempotencyId" })));
|
||||
}
|
||||
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 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>()
|
||||
[Theory, BitAutoData]
|
||||
public async Task LogOrganizationUserEvent_LogsRequiredInfo(OrganizationUser orgUser, EventType eventType, DateTime date,
|
||||
Guid actingUserId, Guid providerId, string ipAddress, DeviceType deviceType, SutProvider<EventService> sutProvider)
|
||||
{
|
||||
{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()
|
||||
var orgAbilities = new Dictionary<Guid, OrganizationAbility>()
|
||||
{
|
||||
IpAddress = ipAddress,
|
||||
DeviceType = deviceType,
|
||||
ProviderId = providerUser.ProviderId,
|
||||
UserId = providerUser.UserId,
|
||||
ProviderUserId = providerUser.Id,
|
||||
Type = eventType,
|
||||
ActingUserId = actingUserId,
|
||||
Date = date
|
||||
}
|
||||
};
|
||||
{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);
|
||||
|
||||
await sutProvider.GetDependency<IEventWriteService>().Received(1).CreateManyAsync(Arg.Is(AssertHelper.AssertPropertyEqual<IEvent>(expected, new[] { "IdempotencyId" })));
|
||||
await sutProvider.Sut.LogOrganizationUserEventAsync(orgUser, eventType, date);
|
||||
|
||||
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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
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" })));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,127 +10,128 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class GroupServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
[Theory, GroupOrganizationAutoData]
|
||||
public async Task SaveAsync_DefaultGroupId_CreatesGroupInRepository(Group group, Organization organization, SutProvider<GroupService> sutProvider)
|
||||
public class GroupServiceTests
|
||||
{
|
||||
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_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;
|
||||
|
||||
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,168 +8,169 @@ using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class HandlebarsMailServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly HandlebarsMailService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IMailDeliveryService _mailDeliveryService;
|
||||
private readonly IMailEnqueuingService _mailEnqueuingService;
|
||||
|
||||
public HandlebarsMailServiceTests()
|
||||
public class HandlebarsMailServiceTests
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
_mailDeliveryService = Substitute.For<IMailDeliveryService>();
|
||||
_mailEnqueuingService = Substitute.For<IMailEnqueuingService>();
|
||||
private readonly HandlebarsMailService _sut;
|
||||
|
||||
_sut = new HandlebarsMailService(
|
||||
_globalSettings,
|
||||
_mailDeliveryService,
|
||||
_mailEnqueuingService
|
||||
);
|
||||
}
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IMailDeliveryService _mailDeliveryService;
|
||||
private readonly IMailEnqueuingService _mailEnqueuingService;
|
||||
|
||||
[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>
|
||||
public HandlebarsMailServiceTests()
|
||||
{
|
||||
// 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(),
|
||||
_globalSettings = new GlobalSettings();
|
||||
_mailDeliveryService = Substitute.For<IMailDeliveryService>();
|
||||
_mailEnqueuingService = Substitute.For<IMailEnqueuingService>();
|
||||
|
||||
}},
|
||||
{ ("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);
|
||||
_sut = new HandlebarsMailService(
|
||||
_globalSettings,
|
||||
_mailDeliveryService,
|
||||
_mailEnqueuingService
|
||||
);
|
||||
}
|
||||
|
||||
async Task InvokeMethod(MethodInfo method)
|
||||
[Fact(Skip = "For local development")]
|
||||
public async Task SendAllEmails()
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
var args = new object[parameters.Length];
|
||||
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
// 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>
|
||||
{
|
||||
if (!namedParameters.TryGetValue((parameters[i].Name, parameters[i].ParameterType), out var value))
|
||||
// TODO: Swith to use env variable
|
||||
{ ("email", typeof(string)), "test@bitwarden.com" },
|
||||
{ ("user", typeof(User)), new User
|
||||
{
|
||||
throw new InvalidOperationException($"Couldn't find a parameter for name '{parameters[i].Name}' and type '{parameters[i].ParameterType.FullName}'");
|
||||
}
|
||||
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(),
|
||||
|
||||
args[i] = value;
|
||||
}},
|
||||
{ ("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);
|
||||
}
|
||||
|
||||
await (Task)method.Invoke(handlebarsService, args);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,28 +3,29 @@ using Bit.Core.Services;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class InMemoryApplicationCacheServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly InMemoryApplicationCacheService _sut;
|
||||
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IProviderRepository _providerRepository;
|
||||
|
||||
public InMemoryApplicationCacheServiceTests()
|
||||
public class InMemoryApplicationCacheServiceTests
|
||||
{
|
||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
_providerRepository = Substitute.For<IProviderRepository>();
|
||||
private readonly InMemoryApplicationCacheService _sut;
|
||||
|
||||
_sut = new InMemoryApplicationCacheService(_organizationRepository, _providerRepository);
|
||||
}
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IProviderRepository _providerRepository;
|
||||
|
||||
// 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);
|
||||
public InMemoryApplicationCacheServiceTests()
|
||||
{
|
||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
_providerRepository = Substitute.For<IProviderRepository>();
|
||||
|
||||
_sut = new InMemoryApplicationCacheService(_organizationRepository, _providerRepository);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,34 +4,35 @@ using Bit.Core.Settings;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class InMemoryServiceBusApplicationCacheServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly InMemoryServiceBusApplicationCacheService _sut;
|
||||
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IProviderRepository _providerRepository;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
public InMemoryServiceBusApplicationCacheServiceTests()
|
||||
public class InMemoryServiceBusApplicationCacheServiceTests
|
||||
{
|
||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
_providerRepository = Substitute.For<IProviderRepository>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
private readonly InMemoryServiceBusApplicationCacheService _sut;
|
||||
|
||||
_sut = new InMemoryServiceBusApplicationCacheService(
|
||||
_organizationRepository,
|
||||
_providerRepository,
|
||||
_globalSettings
|
||||
);
|
||||
}
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IProviderRepository _providerRepository;
|
||||
private readonly GlobalSettings _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);
|
||||
public InMemoryServiceBusApplicationCacheServiceTests()
|
||||
{
|
||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
_providerRepository = Substitute.For<IProviderRepository>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
|
||||
_sut = new InMemoryServiceBusApplicationCacheService(
|
||||
_organizationRepository,
|
||||
_providerRepository,
|
||||
_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,52 +9,53 @@ using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class LicensingServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private static string licenseFilePath(Guid orgId) =>
|
||||
Path.Combine(OrganizationLicenseDirectory.Value, $"{orgId}.json");
|
||||
private static string LicenseDirectory => Path.GetDirectoryName(OrganizationLicenseDirectory.Value);
|
||||
private static Lazy<string> OrganizationLicenseDirectory => new(() =>
|
||||
[SutProviderCustomize]
|
||||
public class LicensingServiceTests
|
||||
{
|
||||
var directory = Path.Combine(Path.GetTempPath(), "organization");
|
||||
if (!Directory.Exists(directory))
|
||||
private static string licenseFilePath(Guid orgId) =>
|
||||
Path.Combine(OrganizationLicenseDirectory.Value, $"{orgId}.json");
|
||||
private static string LicenseDirectory => Path.GetDirectoryName(OrganizationLicenseDirectory.Value);
|
||||
private static Lazy<string> OrganizationLicenseDirectory => new(() =>
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
var directory = Path.Combine(Path.GetTempPath(), "organization");
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
return directory;
|
||||
});
|
||||
|
||||
public static SutProvider<LicensingService> GetSutProvider()
|
||||
{
|
||||
var fixture = new Fixture().WithAutoNSubstitutions();
|
||||
|
||||
var settings = fixture.Create<IGlobalSettings>();
|
||||
settings.LicenseDirectory = LicenseDirectory;
|
||||
settings.SelfHosted = true;
|
||||
|
||||
return new SutProvider<LicensingService>(fixture)
|
||||
.SetDependency(settings)
|
||||
.Create();
|
||||
}
|
||||
return directory;
|
||||
});
|
||||
|
||||
public static SutProvider<LicensingService> GetSutProvider()
|
||||
{
|
||||
var fixture = new Fixture().WithAutoNSubstitutions();
|
||||
|
||||
var settings = fixture.Create<IGlobalSettings>();
|
||||
settings.LicenseDirectory = LicenseDirectory;
|
||||
settings.SelfHosted = true;
|
||||
|
||||
return new SutProvider<LicensingService>(fixture)
|
||||
.SetDependency(settings)
|
||||
.Create();
|
||||
}
|
||||
|
||||
[Theory, BitAutoData, OrganizationLicenseCustomize]
|
||||
public async Task ReadOrganizationLicense(Organization organization, OrganizationLicense license)
|
||||
{
|
||||
var sutProvider = GetSutProvider();
|
||||
|
||||
File.WriteAllText(licenseFilePath(organization.Id), JsonSerializer.Serialize(license));
|
||||
|
||||
var actual = await sutProvider.Sut.ReadOrganizationLicenseAsync(organization);
|
||||
try
|
||||
[Theory, BitAutoData, OrganizationLicenseCustomize]
|
||||
public async Task ReadOrganizationLicense(Organization organization, OrganizationLicense license)
|
||||
{
|
||||
Assert.Equal(JsonSerializer.Serialize(license), JsonSerializer.Serialize(actual));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(OrganizationLicenseDirectory.Value, true);
|
||||
var sutProvider = GetSutProvider();
|
||||
|
||||
File.WriteAllText(licenseFilePath(organization.Id), JsonSerializer.Serialize(license));
|
||||
|
||||
var actual = await sutProvider.Sut.ReadOrganizationLicenseAsync(organization);
|
||||
try
|
||||
{
|
||||
Assert.Equal(JsonSerializer.Serialize(license), JsonSerializer.Serialize(actual));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(OrganizationLicenseDirectory.Value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,75 +11,194 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class LocalAttachmentStorageServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
|
||||
private void AssertFileCreation(string expectedPath, string expectedFileContents)
|
||||
public class LocalAttachmentStorageServiceTests
|
||||
{
|
||||
Assert.True(File.Exists(expectedPath));
|
||||
Assert.Equal(expectedFileContents, File.ReadAllText(expectedPath));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(UserCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(UserCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(UserCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task UploadNewAttachmentAsync_Success(string stream, Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
private void AssertFileCreation(string expectedPath, string expectedFileContents)
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
await sutProvider.Sut.UploadNewAttachmentAsync(new MemoryStream(Encoding.UTF8.GetBytes(stream)),
|
||||
cipher, attachmentData);
|
||||
|
||||
AssertFileCreation($"{tempDirectory}/{cipher.Id}/{attachmentData.AttachmentId}", stream);
|
||||
Assert.True(File.Exists(expectedPath));
|
||||
Assert.Equal(expectedFileContents, File.ReadAllText(expectedPath));
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task UploadShareAttachmentAsync_Success(string stream, Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(UserCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(UserCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(UserCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task UploadNewAttachmentAsync_Success(string stream, Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
await sutProvider.Sut.UploadShareAttachmentAsync(new MemoryStream(Encoding.UTF8.GetBytes(stream)),
|
||||
cipher.Id, cipher.OrganizationId.Value, attachmentData);
|
||||
await sutProvider.Sut.UploadNewAttachmentAsync(new MemoryStream(Encoding.UTF8.GetBytes(stream)),
|
||||
cipher, attachmentData);
|
||||
|
||||
AssertFileCreation($"{tempDirectory}/temp/{cipher.Id}/{cipher.OrganizationId}/{attachmentData.AttachmentId}", stream);
|
||||
AssertFileCreation($"{tempDirectory}/{cipher.Id}/{attachmentData.AttachmentId}", stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task StartShareAttachmentAsync_NoSource_NoWork(Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task UploadShareAttachmentAsync_Success(string stream, Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
await sutProvider.Sut.StartShareAttachmentAsync(cipher.Id, cipher.OrganizationId.Value, attachmentData);
|
||||
await sutProvider.Sut.UploadShareAttachmentAsync(new MemoryStream(Encoding.UTF8.GetBytes(stream)),
|
||||
cipher.Id, cipher.OrganizationId.Value, attachmentData);
|
||||
|
||||
Assert.False(File.Exists($"{tempDirectory}/{cipher.Id}/{attachmentData.AttachmentId}"));
|
||||
Assert.False(File.Exists($"{tempDirectory}/{cipher.Id}/{attachmentData.AttachmentId}"));
|
||||
AssertFileCreation($"{tempDirectory}/temp/{cipher.Id}/{cipher.OrganizationId}/{attachmentData.AttachmentId}", stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task StartShareAttachmentAsync_NoDest_NoWork(string source, Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task StartShareAttachmentAsync_NoSource_NoWork(Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
await sutProvider.Sut.StartShareAttachmentAsync(cipher.Id, cipher.OrganizationId.Value, attachmentData);
|
||||
|
||||
Assert.False(File.Exists($"{tempDirectory}/{cipher.Id}/{attachmentData.AttachmentId}"));
|
||||
Assert.False(File.Exists($"{tempDirectory}/{cipher.Id}/{attachmentData.AttachmentId}"));
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task StartShareAttachmentAsync_NoDest_NoWork(string source, Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
var sourcePath = $"{tempDirectory}/temp/{cipher.Id}/{cipher.OrganizationId}/{attachmentData.AttachmentId}";
|
||||
var destPath = $"{tempDirectory}/{cipher.Id}/{attachmentData.AttachmentId}";
|
||||
var rollBackPath = $"{tempDirectory}/temp/{cipher.Id}/{attachmentData.AttachmentId}";
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(sourcePath));
|
||||
File.WriteAllText(sourcePath, source);
|
||||
|
||||
await sutProvider.Sut.StartShareAttachmentAsync(cipher.Id, cipher.OrganizationId.Value, attachmentData);
|
||||
|
||||
Assert.True(File.Exists(sourcePath));
|
||||
Assert.Equal(source, File.ReadAllText(sourcePath));
|
||||
Assert.False(File.Exists(destPath));
|
||||
Assert.False(File.Exists(rollBackPath));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task StartShareAttachmentAsync_Success(string source, string destOriginal, Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
{
|
||||
await StartShareAttachmentAsync(source, destOriginal, cipher, attachmentData, tempDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task RollbackShareAttachmentAsync_Success(string source, string destOriginal, Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
var sourcePath = $"{tempDirectory}/temp/{cipher.Id}/{cipher.OrganizationId}/{attachmentData.AttachmentId}";
|
||||
var destPath = $"{tempDirectory}/{cipher.Id}/{attachmentData.AttachmentId}";
|
||||
var rollBackPath = $"{tempDirectory}/temp/{cipher.Id}/{attachmentData.AttachmentId}";
|
||||
|
||||
await StartShareAttachmentAsync(source, destOriginal, cipher, attachmentData, tempDirectory);
|
||||
await sutProvider.Sut.RollbackShareAttachmentAsync(cipher.Id, cipher.OrganizationId.Value, attachmentData, "Not Used Here");
|
||||
|
||||
Assert.True(File.Exists(destPath));
|
||||
Assert.Equal(destOriginal, File.ReadAllText(destPath));
|
||||
Assert.False(File.Exists(sourcePath));
|
||||
Assert.False(File.Exists(rollBackPath));
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(UserCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(UserCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(UserCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task DeleteAttachmentAsync_Success(Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
var expectedPath = $"{tempDirectory}/{cipher.Id}/{attachmentData.AttachmentId}";
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(expectedPath));
|
||||
File.Create(expectedPath).Close();
|
||||
|
||||
await sutProvider.Sut.DeleteAttachmentAsync(cipher.Id, attachmentData);
|
||||
|
||||
Assert.False(File.Exists(expectedPath));
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData]
|
||||
[InlineOrganizationCipherAutoData]
|
||||
public async Task CleanupAsync_Succes(Cipher cipher)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
var tempPath = $"{tempDirectory}/temp/{cipher.Id}";
|
||||
var permPath = $"{tempDirectory}/{cipher.Id}";
|
||||
Directory.CreateDirectory(tempPath);
|
||||
Directory.CreateDirectory(permPath);
|
||||
|
||||
await sutProvider.Sut.CleanupAsync(cipher.Id);
|
||||
|
||||
Assert.False(Directory.Exists(tempPath));
|
||||
Assert.True(Directory.Exists(permPath));
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData]
|
||||
[InlineOrganizationCipherAutoData]
|
||||
public async Task DeleteAttachmentsForCipherAsync_Succes(Cipher cipher)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
var tempPath = $"{tempDirectory}/temp/{cipher.Id}";
|
||||
var permPath = $"{tempDirectory}/{cipher.Id}";
|
||||
Directory.CreateDirectory(tempPath);
|
||||
Directory.CreateDirectory(permPath);
|
||||
|
||||
await sutProvider.Sut.DeleteAttachmentsForCipherAsync(cipher.Id);
|
||||
|
||||
Assert.True(Directory.Exists(tempPath));
|
||||
Assert.False(Directory.Exists(permPath));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StartShareAttachmentAsync(string source, string destOriginal, Cipher cipher,
|
||||
CipherAttachment.MetaData attachmentData, TempDirectory tempDirectory)
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
@@ -87,144 +206,26 @@ public class LocalAttachmentStorageServiceTests
|
||||
var destPath = $"{tempDirectory}/{cipher.Id}/{attachmentData.AttachmentId}";
|
||||
var rollBackPath = $"{tempDirectory}/temp/{cipher.Id}/{attachmentData.AttachmentId}";
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(sourcePath));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destPath));
|
||||
File.WriteAllText(sourcePath, source);
|
||||
File.WriteAllText(destPath, destOriginal);
|
||||
|
||||
await sutProvider.Sut.StartShareAttachmentAsync(cipher.Id, cipher.OrganizationId.Value, attachmentData);
|
||||
|
||||
Assert.True(File.Exists(sourcePath));
|
||||
Assert.Equal(source, File.ReadAllText(sourcePath));
|
||||
Assert.False(File.Exists(destPath));
|
||||
Assert.False(File.Exists(rollBackPath));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task StartShareAttachmentAsync_Success(string source, string destOriginal, Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
{
|
||||
await StartShareAttachmentAsync(source, destOriginal, cipher, attachmentData, tempDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(OrganizationCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task RollbackShareAttachmentAsync_Success(string source, string destOriginal, Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
var sourcePath = $"{tempDirectory}/temp/{cipher.Id}/{cipher.OrganizationId}/{attachmentData.AttachmentId}";
|
||||
var destPath = $"{tempDirectory}/{cipher.Id}/{attachmentData.AttachmentId}";
|
||||
var rollBackPath = $"{tempDirectory}/temp/{cipher.Id}/{attachmentData.AttachmentId}";
|
||||
|
||||
await StartShareAttachmentAsync(source, destOriginal, cipher, attachmentData, tempDirectory);
|
||||
await sutProvider.Sut.RollbackShareAttachmentAsync(cipher.Id, cipher.OrganizationId.Value, attachmentData, "Not Used Here");
|
||||
|
||||
Assert.True(File.Exists(destPath));
|
||||
Assert.Equal(destOriginal, File.ReadAllText(destPath));
|
||||
Assert.False(File.Exists(sourcePath));
|
||||
Assert.False(File.Exists(rollBackPath));
|
||||
Assert.True(File.Exists(destPath));
|
||||
Assert.Equal(source, File.ReadAllText(destPath));
|
||||
Assert.True(File.Exists(rollBackPath));
|
||||
Assert.Equal(destOriginal, File.ReadAllText(rollBackPath));
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(UserCipher), typeof(MetaData) })]
|
||||
[InlineCustomAutoData(new[] { typeof(UserCipher), typeof(MetaDataWithoutContainer) })]
|
||||
[InlineCustomAutoData(new[] { typeof(UserCipher), typeof(MetaDataWithoutKey) })]
|
||||
public async Task DeleteAttachmentAsync_Success(Cipher cipher, CipherAttachment.MetaData attachmentData)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
private SutProvider<LocalAttachmentStorageService> GetSutProvider(TempDirectory tempDirectory)
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
var fixture = new Fixture().WithAutoNSubstitutions();
|
||||
fixture.Freeze<IGlobalSettings>().Attachment.BaseDirectory.Returns(tempDirectory.Directory);
|
||||
fixture.Freeze<IGlobalSettings>().Attachment.BaseUrl.Returns(Guid.NewGuid().ToString());
|
||||
|
||||
var expectedPath = $"{tempDirectory}/{cipher.Id}/{attachmentData.AttachmentId}";
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(expectedPath));
|
||||
File.Create(expectedPath).Close();
|
||||
|
||||
await sutProvider.Sut.DeleteAttachmentAsync(cipher.Id, attachmentData);
|
||||
|
||||
Assert.False(File.Exists(expectedPath));
|
||||
return new SutProvider<LocalAttachmentStorageService>(fixture).Create();
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData]
|
||||
[InlineOrganizationCipherAutoData]
|
||||
public async Task CleanupAsync_Succes(Cipher cipher)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
var tempPath = $"{tempDirectory}/temp/{cipher.Id}";
|
||||
var permPath = $"{tempDirectory}/{cipher.Id}";
|
||||
Directory.CreateDirectory(tempPath);
|
||||
Directory.CreateDirectory(permPath);
|
||||
|
||||
await sutProvider.Sut.CleanupAsync(cipher.Id);
|
||||
|
||||
Assert.False(Directory.Exists(tempPath));
|
||||
Assert.True(Directory.Exists(permPath));
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineUserCipherAutoData]
|
||||
[InlineOrganizationCipherAutoData]
|
||||
public async Task DeleteAttachmentsForCipherAsync_Succes(Cipher cipher)
|
||||
{
|
||||
using (var tempDirectory = new TempDirectory())
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
var tempPath = $"{tempDirectory}/temp/{cipher.Id}";
|
||||
var permPath = $"{tempDirectory}/{cipher.Id}";
|
||||
Directory.CreateDirectory(tempPath);
|
||||
Directory.CreateDirectory(permPath);
|
||||
|
||||
await sutProvider.Sut.DeleteAttachmentsForCipherAsync(cipher.Id);
|
||||
|
||||
Assert.True(Directory.Exists(tempPath));
|
||||
Assert.False(Directory.Exists(permPath));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StartShareAttachmentAsync(string source, string destOriginal, Cipher cipher,
|
||||
CipherAttachment.MetaData attachmentData, TempDirectory tempDirectory)
|
||||
{
|
||||
var sutProvider = GetSutProvider(tempDirectory);
|
||||
|
||||
var sourcePath = $"{tempDirectory}/temp/{cipher.Id}/{cipher.OrganizationId}/{attachmentData.AttachmentId}";
|
||||
var destPath = $"{tempDirectory}/{cipher.Id}/{attachmentData.AttachmentId}";
|
||||
var rollBackPath = $"{tempDirectory}/temp/{cipher.Id}/{attachmentData.AttachmentId}";
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(sourcePath));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destPath));
|
||||
File.WriteAllText(sourcePath, source);
|
||||
File.WriteAllText(destPath, destOriginal);
|
||||
|
||||
await sutProvider.Sut.StartShareAttachmentAsync(cipher.Id, cipher.OrganizationId.Value, attachmentData);
|
||||
|
||||
Assert.False(File.Exists(sourcePath));
|
||||
Assert.True(File.Exists(destPath));
|
||||
Assert.Equal(source, File.ReadAllText(destPath));
|
||||
Assert.True(File.Exists(rollBackPath));
|
||||
Assert.Equal(destOriginal, File.ReadAllText(rollBackPath));
|
||||
}
|
||||
|
||||
private SutProvider<LocalAttachmentStorageService> GetSutProvider(TempDirectory tempDirectory)
|
||||
{
|
||||
var fixture = new Fixture().WithAutoNSubstitutions();
|
||||
fixture.Freeze<IGlobalSettings>().Attachment.BaseDirectory.Returns(tempDirectory.Directory);
|
||||
fixture.Freeze<IGlobalSettings>().Attachment.BaseUrl.Returns(Guid.NewGuid().ToString());
|
||||
|
||||
return new SutProvider<LocalAttachmentStorageService>(fixture).Create();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,34 +4,35 @@ using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class MailKitSmtpMailDeliveryServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly MailKitSmtpMailDeliveryService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ILogger<MailKitSmtpMailDeliveryService> _logger;
|
||||
|
||||
public MailKitSmtpMailDeliveryServiceTests()
|
||||
public class MailKitSmtpMailDeliveryServiceTests
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
_logger = Substitute.For<ILogger<MailKitSmtpMailDeliveryService>>();
|
||||
private readonly MailKitSmtpMailDeliveryService _sut;
|
||||
|
||||
_globalSettings.Mail.Smtp.Host = "unittests.example.com";
|
||||
_globalSettings.Mail.ReplyToEmail = "noreply@unittests.example.com";
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ILogger<MailKitSmtpMailDeliveryService> _logger;
|
||||
|
||||
_sut = new MailKitSmtpMailDeliveryService(
|
||||
_globalSettings,
|
||||
_logger
|
||||
);
|
||||
}
|
||||
public MailKitSmtpMailDeliveryServiceTests()
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
_logger = Substitute.For<ILogger<MailKitSmtpMailDeliveryService>>();
|
||||
|
||||
// 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);
|
||||
_globalSettings.Mail.Smtp.Host = "unittests.example.com";
|
||||
_globalSettings.Mail.ReplyToEmail = "noreply@unittests.example.com";
|
||||
|
||||
_sut = new MailKitSmtpMailDeliveryService(
|
||||
_globalSettings,
|
||||
_logger
|
||||
);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,49 +6,50 @@ using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class MultiServicePushNotificationServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly MultiServicePushNotificationService _sut;
|
||||
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
private readonly IDeviceRepository _deviceRepository;
|
||||
private readonly IInstallationDeviceRepository _installationDeviceRepository;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ILogger<MultiServicePushNotificationService> _logger;
|
||||
private readonly ILogger<RelayPushNotificationService> _relayLogger;
|
||||
private readonly ILogger<NotificationsApiPushNotificationService> _hubLogger;
|
||||
|
||||
public MultiServicePushNotificationServiceTests()
|
||||
public class MultiServicePushNotificationServiceTests
|
||||
{
|
||||
_httpFactory = Substitute.For<IHttpClientFactory>();
|
||||
_deviceRepository = Substitute.For<IDeviceRepository>();
|
||||
_installationDeviceRepository = Substitute.For<IInstallationDeviceRepository>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
_httpContextAccessor = Substitute.For<IHttpContextAccessor>();
|
||||
_logger = Substitute.For<ILogger<MultiServicePushNotificationService>>();
|
||||
_relayLogger = Substitute.For<ILogger<RelayPushNotificationService>>();
|
||||
_hubLogger = Substitute.For<ILogger<NotificationsApiPushNotificationService>>();
|
||||
private readonly MultiServicePushNotificationService _sut;
|
||||
|
||||
_sut = new MultiServicePushNotificationService(
|
||||
_httpFactory,
|
||||
_deviceRepository,
|
||||
_installationDeviceRepository,
|
||||
_globalSettings,
|
||||
_httpContextAccessor,
|
||||
_logger,
|
||||
_relayLogger,
|
||||
_hubLogger
|
||||
);
|
||||
}
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
private readonly IDeviceRepository _deviceRepository;
|
||||
private readonly IInstallationDeviceRepository _installationDeviceRepository;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ILogger<MultiServicePushNotificationService> _logger;
|
||||
private readonly ILogger<RelayPushNotificationService> _relayLogger;
|
||||
private readonly ILogger<NotificationsApiPushNotificationService> _hubLogger;
|
||||
|
||||
// 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);
|
||||
public MultiServicePushNotificationServiceTests()
|
||||
{
|
||||
_httpFactory = Substitute.For<IHttpClientFactory>();
|
||||
_deviceRepository = Substitute.For<IDeviceRepository>();
|
||||
_installationDeviceRepository = Substitute.For<IInstallationDeviceRepository>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
_httpContextAccessor = Substitute.For<IHttpContextAccessor>();
|
||||
_logger = Substitute.For<ILogger<MultiServicePushNotificationService>>();
|
||||
_relayLogger = Substitute.For<ILogger<RelayPushNotificationService>>();
|
||||
_hubLogger = Substitute.For<ILogger<NotificationsApiPushNotificationService>>();
|
||||
|
||||
_sut = new MultiServicePushNotificationService(
|
||||
_httpFactory,
|
||||
_deviceRepository,
|
||||
_installationDeviceRepository,
|
||||
_globalSettings,
|
||||
_httpContextAccessor,
|
||||
_logger,
|
||||
_relayLogger,
|
||||
_hubLogger
|
||||
);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,34 +5,35 @@ using Microsoft.AspNetCore.Http;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class NotificationHubPushNotificationServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly NotificationHubPushNotificationService _sut;
|
||||
|
||||
private readonly IInstallationDeviceRepository _installationDeviceRepository;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public NotificationHubPushNotificationServiceTests()
|
||||
public class NotificationHubPushNotificationServiceTests
|
||||
{
|
||||
_installationDeviceRepository = Substitute.For<IInstallationDeviceRepository>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
_httpContextAccessor = Substitute.For<IHttpContextAccessor>();
|
||||
private readonly NotificationHubPushNotificationService _sut;
|
||||
|
||||
_sut = new NotificationHubPushNotificationService(
|
||||
_installationDeviceRepository,
|
||||
_globalSettings,
|
||||
_httpContextAccessor
|
||||
);
|
||||
}
|
||||
private readonly IInstallationDeviceRepository _installationDeviceRepository;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _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);
|
||||
public NotificationHubPushNotificationServiceTests()
|
||||
{
|
||||
_installationDeviceRepository = Substitute.For<IInstallationDeviceRepository>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
_httpContextAccessor = Substitute.For<IHttpContextAccessor>();
|
||||
|
||||
_sut = new NotificationHubPushNotificationService(
|
||||
_installationDeviceRepository,
|
||||
_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,31 +4,32 @@ using Bit.Core.Settings;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class NotificationHubPushRegistrationServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly NotificationHubPushRegistrationService _sut;
|
||||
|
||||
private readonly IInstallationDeviceRepository _installationDeviceRepository;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
public NotificationHubPushRegistrationServiceTests()
|
||||
public class NotificationHubPushRegistrationServiceTests
|
||||
{
|
||||
_installationDeviceRepository = Substitute.For<IInstallationDeviceRepository>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
private readonly NotificationHubPushRegistrationService _sut;
|
||||
|
||||
_sut = new NotificationHubPushRegistrationService(
|
||||
_installationDeviceRepository,
|
||||
_globalSettings
|
||||
);
|
||||
}
|
||||
private readonly IInstallationDeviceRepository _installationDeviceRepository;
|
||||
private readonly GlobalSettings _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);
|
||||
public NotificationHubPushRegistrationServiceTests()
|
||||
{
|
||||
_installationDeviceRepository = Substitute.For<IInstallationDeviceRepository>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
|
||||
_sut = new NotificationHubPushRegistrationService(
|
||||
_installationDeviceRepository,
|
||||
_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,37 +5,38 @@ using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class NotificationsApiPushNotificationServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly NotificationsApiPushNotificationService _sut;
|
||||
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ILogger<NotificationsApiPushNotificationService> _logger;
|
||||
|
||||
public NotificationsApiPushNotificationServiceTests()
|
||||
public class NotificationsApiPushNotificationServiceTests
|
||||
{
|
||||
_httpFactory = Substitute.For<IHttpClientFactory>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
_httpContextAccessor = Substitute.For<IHttpContextAccessor>();
|
||||
_logger = Substitute.For<ILogger<NotificationsApiPushNotificationService>>();
|
||||
private readonly NotificationsApiPushNotificationService _sut;
|
||||
|
||||
_sut = new NotificationsApiPushNotificationService(
|
||||
_httpFactory,
|
||||
_globalSettings,
|
||||
_httpContextAccessor,
|
||||
_logger
|
||||
);
|
||||
}
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ILogger<NotificationsApiPushNotificationService> _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);
|
||||
public NotificationsApiPushNotificationServiceTests()
|
||||
{
|
||||
_httpFactory = Substitute.For<IHttpClientFactory>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
_httpContextAccessor = Substitute.For<IHttpContextAccessor>();
|
||||
_logger = Substitute.For<ILogger<NotificationsApiPushNotificationService>>();
|
||||
|
||||
_sut = new NotificationsApiPushNotificationService(
|
||||
_httpFactory,
|
||||
_globalSettings,
|
||||
_httpContextAccessor,
|
||||
_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,391 +10,392 @@ using NSubstitute;
|
||||
using Xunit;
|
||||
using PolicyFixtures = Bit.Core.Test.AutoFixture.PolicyFixtures;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class PolicyServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_OrganizationDoesNotExist_ThrowsBadRequest(
|
||||
[PolicyFixtures.Policy(PolicyType.DisableSend)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
[SutProviderCustomize]
|
||||
public class PolicyServiceTests
|
||||
{
|
||||
SetupOrg(sutProvider, policy.OrganizationId, null);
|
||||
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
|
||||
Assert.Contains("Organization not found", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
|
||||
await sutProvider.GetDependency<IEventService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.LogPolicyEventAsync(default, default, default);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_OrganizationCannotUsePolicies_ThrowsBadRequest(
|
||||
[PolicyFixtures.Policy(PolicyType.DisableSend)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
var orgId = Guid.NewGuid();
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_OrganizationDoesNotExist_ThrowsBadRequest(
|
||||
[PolicyFixtures.Policy(PolicyType.DisableSend)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
UsePolicies = false,
|
||||
});
|
||||
SetupOrg(sutProvider, policy.OrganizationId, null);
|
||||
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
|
||||
Assert.Contains("cannot use policies", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains("Organization not found", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
|
||||
await sutProvider.GetDependency<IEventService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.LogPolicyEventAsync(default, default, default);
|
||||
}
|
||||
await sutProvider.GetDependency<IEventService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.LogPolicyEventAsync(default, default, default);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_SingleOrg_RequireSsoEnabled_ThrowsBadRequest(
|
||||
[PolicyFixtures.Policy(PolicyType.SingleOrg)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
policy.Enabled = false;
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_OrganizationCannotUsePolicies_ThrowsBadRequest(
|
||||
[PolicyFixtures.Policy(PolicyType.DisableSend)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
});
|
||||
var orgId = Guid.NewGuid();
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(policy.OrganizationId, PolicyType.RequireSso)
|
||||
.Returns(Task.FromResult(new Policy { Enabled = true }));
|
||||
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
|
||||
Assert.Contains("Single Sign-On Authentication policy is enabled.", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
|
||||
await sutProvider.GetDependency<IEventService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.LogPolicyEventAsync(default, default, default);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_SingleOrg_VaultTimeoutEnabled_ThrowsBadRequest([PolicyFixtures.Policy(Enums.PolicyType.SingleOrg)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
policy.Enabled = false;
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
{
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(policy.OrganizationId, Enums.PolicyType.MaximumVaultTimeout)
|
||||
.Returns(new Policy { Enabled = true });
|
||||
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
|
||||
Assert.Contains("Maximum Vault Timeout policy is enabled.", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PolicyType.SingleOrg)]
|
||||
[BitAutoData(PolicyType.RequireSso)]
|
||||
public async Task SaveAsync_PolicyRequiredByKeyConnector_DisablePolicy_ThrowsBadRequest(
|
||||
Enums.PolicyType policyType,
|
||||
Policy policy,
|
||||
SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
policy.Enabled = false;
|
||||
policy.Type = policyType;
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
{
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
});
|
||||
|
||||
var ssoConfig = new SsoConfig { Enabled = true };
|
||||
var data = new SsoConfigurationData { KeyConnectorEnabled = true };
|
||||
ssoConfig.SetData(data);
|
||||
|
||||
sutProvider.GetDependency<ISsoConfigRepository>()
|
||||
.GetByOrganizationIdAsync(policy.OrganizationId)
|
||||
.Returns(ssoConfig);
|
||||
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
|
||||
Assert.Contains("Key Connector is enabled.", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_RequireSsoPolicy_NotEnabled_ThrowsBadRequestAsync(
|
||||
[PolicyFixtures.Policy(Enums.PolicyType.RequireSso)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
policy.Enabled = true;
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
{
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(policy.OrganizationId, PolicyType.SingleOrg)
|
||||
.Returns(Task.FromResult(new Policy { Enabled = false }));
|
||||
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
|
||||
Assert.Contains("Single Organization policy not enabled.", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
|
||||
await sutProvider.GetDependency<IEventService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.LogPolicyEventAsync(default, default, default);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_NewPolicy_Created(
|
||||
[PolicyFixtures.Policy(PolicyType.ResetPassword)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
policy.Id = default;
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
{
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
});
|
||||
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
await sutProvider.Sut.SaveAsync(policy, Substitute.For<IUserService>(), Substitute.For<IOrganizationService>(), Guid.NewGuid());
|
||||
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogPolicyEventAsync(policy, EventType.Policy_Updated);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>().Received()
|
||||
.UpsertAsync(policy);
|
||||
|
||||
Assert.True(policy.CreationDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
Assert.True(policy.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_VaultTimeoutPolicy_NotEnabled_ThrowsBadRequestAsync(
|
||||
[PolicyFixtures.Policy(PolicyType.MaximumVaultTimeout)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
policy.Enabled = true;
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
{
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(policy.OrganizationId, Enums.PolicyType.SingleOrg)
|
||||
.Returns(Task.FromResult(new Policy { Enabled = false }));
|
||||
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
|
||||
Assert.Contains("Single Organization policy not enabled.", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
|
||||
await sutProvider.GetDependency<IEventService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.LogPolicyEventAsync(default, default, default);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_ExistingPolicy_UpdateTwoFactor(
|
||||
[PolicyFixtures.Policy(PolicyType.TwoFactorAuthentication)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
// If the policy that this is updating isn't enabled then do some work now that the current one is enabled
|
||||
|
||||
var org = new Organization
|
||||
{
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
Name = "TEST",
|
||||
};
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, org);
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByIdAsync(policy.Id)
|
||||
.Returns(new Policy
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
{
|
||||
Id = policy.Id,
|
||||
Type = PolicyType.TwoFactorAuthentication,
|
||||
Enabled = false,
|
||||
UsePolicies = false,
|
||||
});
|
||||
|
||||
var orgUserDetail = new Core.Models.Data.Organizations.OrganizationUsers.OrganizationUserUserDetails
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Status = OrganizationUserStatusType.Accepted,
|
||||
Type = OrganizationUserType.User,
|
||||
// Needs to be different from what is passed in as the savingUserId to Sut.SaveAsync
|
||||
Email = "test@bitwarden.com",
|
||||
Name = "TEST",
|
||||
UserId = Guid.NewGuid(),
|
||||
};
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyDetailsByOrganizationAsync(policy.OrganizationId)
|
||||
.Returns(new List<Core.Models.Data.Organizations.OrganizationUsers.OrganizationUserUserDetails>
|
||||
Assert.Contains("cannot use policies", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
|
||||
await sutProvider.GetDependency<IEventService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.LogPolicyEventAsync(default, default, default);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_SingleOrg_RequireSsoEnabled_ThrowsBadRequest(
|
||||
[PolicyFixtures.Policy(PolicyType.SingleOrg)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
policy.Enabled = false;
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
{
|
||||
orgUserDetail,
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
});
|
||||
|
||||
var userService = Substitute.For<IUserService>();
|
||||
var organizationService = Substitute.For<IOrganizationService>();
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(policy.OrganizationId, PolicyType.RequireSso)
|
||||
.Returns(Task.FromResult(new Policy { Enabled = true }));
|
||||
|
||||
userService.TwoFactorIsEnabledAsync(orgUserDetail)
|
||||
.Returns(false);
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
|
||||
var utcNow = DateTime.UtcNow;
|
||||
Assert.Contains("Single Sign-On Authentication policy is enabled.", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var savingUserId = Guid.NewGuid();
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
|
||||
await sutProvider.Sut.SaveAsync(policy, userService, organizationService, savingUserId);
|
||||
await sutProvider.GetDependency<IEventService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.LogPolicyEventAsync(default, default, default);
|
||||
}
|
||||
|
||||
await organizationService.Received()
|
||||
.DeleteUserAsync(policy.OrganizationId, orgUserDetail.Id, savingUserId);
|
||||
|
||||
await sutProvider.GetDependency<IMailService>().Received()
|
||||
.SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(org.Name, orgUserDetail.Email);
|
||||
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogPolicyEventAsync(policy, EventType.Policy_Updated);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>().Received()
|
||||
.UpsertAsync(policy);
|
||||
|
||||
Assert.True(policy.CreationDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
Assert.True(policy.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_ExistingPolicy_UpdateSingleOrg(
|
||||
[PolicyFixtures.Policy(PolicyType.TwoFactorAuthentication)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
// If the policy that this is updating isn't enabled then do some work now that the current one is enabled
|
||||
|
||||
var org = new Organization
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_SingleOrg_VaultTimeoutEnabled_ThrowsBadRequest([PolicyFixtures.Policy(Enums.PolicyType.SingleOrg)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
Name = "TEST",
|
||||
};
|
||||
policy.Enabled = false;
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, org);
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByIdAsync(policy.Id)
|
||||
.Returns(new Policy
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
{
|
||||
Id = policy.Id,
|
||||
Type = PolicyType.SingleOrg,
|
||||
Enabled = false,
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
});
|
||||
|
||||
var orgUserDetail = new Core.Models.Data.Organizations.OrganizationUsers.OrganizationUserUserDetails
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Status = OrganizationUserStatusType.Accepted,
|
||||
Type = OrganizationUserType.User,
|
||||
// Needs to be different from what is passed in as the savingUserId to Sut.SaveAsync
|
||||
Email = "test@bitwarden.com",
|
||||
Name = "TEST",
|
||||
UserId = Guid.NewGuid(),
|
||||
};
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(policy.OrganizationId, Enums.PolicyType.MaximumVaultTimeout)
|
||||
.Returns(new Policy { Enabled = true });
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyDetailsByOrganizationAsync(policy.OrganizationId)
|
||||
.Returns(new List<Core.Models.Data.Organizations.OrganizationUsers.OrganizationUserUserDetails>
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
|
||||
Assert.Contains("Maximum Vault Timeout policy is enabled.", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PolicyType.SingleOrg)]
|
||||
[BitAutoData(PolicyType.RequireSso)]
|
||||
public async Task SaveAsync_PolicyRequiredByKeyConnector_DisablePolicy_ThrowsBadRequest(
|
||||
Enums.PolicyType policyType,
|
||||
Policy policy,
|
||||
SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
policy.Enabled = false;
|
||||
policy.Type = policyType;
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
{
|
||||
orgUserDetail,
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
});
|
||||
|
||||
var userService = Substitute.For<IUserService>();
|
||||
var organizationService = Substitute.For<IOrganizationService>();
|
||||
var ssoConfig = new SsoConfig { Enabled = true };
|
||||
var data = new SsoConfigurationData { KeyConnectorEnabled = true };
|
||||
ssoConfig.SetData(data);
|
||||
|
||||
userService.TwoFactorIsEnabledAsync(orgUserDetail)
|
||||
.Returns(false);
|
||||
sutProvider.GetDependency<ISsoConfigRepository>()
|
||||
.GetByOrganizationIdAsync(policy.OrganizationId)
|
||||
.Returns(ssoConfig);
|
||||
|
||||
var utcNow = DateTime.UtcNow;
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
|
||||
var savingUserId = Guid.NewGuid();
|
||||
Assert.Contains("Key Connector is enabled.", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
await sutProvider.Sut.SaveAsync(policy, userService, organizationService, savingUserId);
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogPolicyEventAsync(policy, EventType.Policy_Updated);
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_RequireSsoPolicy_NotEnabled_ThrowsBadRequestAsync(
|
||||
[PolicyFixtures.Policy(Enums.PolicyType.RequireSso)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
policy.Enabled = true;
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>().Received()
|
||||
.UpsertAsync(policy);
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
{
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
});
|
||||
|
||||
Assert.True(policy.CreationDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
Assert.True(policy.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(policy.OrganizationId, PolicyType.SingleOrg)
|
||||
.Returns(Task.FromResult(new Policy { Enabled = false }));
|
||||
|
||||
private static void SetupOrg(SutProvider<PolicyService> sutProvider, Guid organizationId, Organization organization)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.GetByIdAsync(organizationId)
|
||||
.Returns(Task.FromResult(organization));
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
|
||||
Assert.Contains("Single Organization policy not enabled.", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
|
||||
await sutProvider.GetDependency<IEventService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.LogPolicyEventAsync(default, default, default);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_NewPolicy_Created(
|
||||
[PolicyFixtures.Policy(PolicyType.ResetPassword)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
policy.Id = default;
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
{
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
});
|
||||
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
await sutProvider.Sut.SaveAsync(policy, Substitute.For<IUserService>(), Substitute.For<IOrganizationService>(), Guid.NewGuid());
|
||||
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogPolicyEventAsync(policy, EventType.Policy_Updated);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>().Received()
|
||||
.UpsertAsync(policy);
|
||||
|
||||
Assert.True(policy.CreationDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
Assert.True(policy.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_VaultTimeoutPolicy_NotEnabled_ThrowsBadRequestAsync(
|
||||
[PolicyFixtures.Policy(PolicyType.MaximumVaultTimeout)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
policy.Enabled = true;
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, new Organization
|
||||
{
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(policy.OrganizationId, Enums.PolicyType.SingleOrg)
|
||||
.Returns(Task.FromResult(new Policy { Enabled = false }));
|
||||
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy,
|
||||
Substitute.For<IUserService>(),
|
||||
Substitute.For<IOrganizationService>(),
|
||||
Guid.NewGuid()));
|
||||
|
||||
Assert.Contains("Single Organization policy not enabled.", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
|
||||
await sutProvider.GetDependency<IEventService>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.LogPolicyEventAsync(default, default, default);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_ExistingPolicy_UpdateTwoFactor(
|
||||
[PolicyFixtures.Policy(PolicyType.TwoFactorAuthentication)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
// If the policy that this is updating isn't enabled then do some work now that the current one is enabled
|
||||
|
||||
var org = new Organization
|
||||
{
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
Name = "TEST",
|
||||
};
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, org);
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByIdAsync(policy.Id)
|
||||
.Returns(new Policy
|
||||
{
|
||||
Id = policy.Id,
|
||||
Type = PolicyType.TwoFactorAuthentication,
|
||||
Enabled = false,
|
||||
});
|
||||
|
||||
var orgUserDetail = new Core.Models.Data.Organizations.OrganizationUsers.OrganizationUserUserDetails
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Status = OrganizationUserStatusType.Accepted,
|
||||
Type = OrganizationUserType.User,
|
||||
// Needs to be different from what is passed in as the savingUserId to Sut.SaveAsync
|
||||
Email = "test@bitwarden.com",
|
||||
Name = "TEST",
|
||||
UserId = Guid.NewGuid(),
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyDetailsByOrganizationAsync(policy.OrganizationId)
|
||||
.Returns(new List<Core.Models.Data.Organizations.OrganizationUsers.OrganizationUserUserDetails>
|
||||
{
|
||||
orgUserDetail,
|
||||
});
|
||||
|
||||
var userService = Substitute.For<IUserService>();
|
||||
var organizationService = Substitute.For<IOrganizationService>();
|
||||
|
||||
userService.TwoFactorIsEnabledAsync(orgUserDetail)
|
||||
.Returns(false);
|
||||
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var savingUserId = Guid.NewGuid();
|
||||
|
||||
await sutProvider.Sut.SaveAsync(policy, userService, organizationService, savingUserId);
|
||||
|
||||
await organizationService.Received()
|
||||
.DeleteUserAsync(policy.OrganizationId, orgUserDetail.Id, savingUserId);
|
||||
|
||||
await sutProvider.GetDependency<IMailService>().Received()
|
||||
.SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(org.Name, orgUserDetail.Email);
|
||||
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogPolicyEventAsync(policy, EventType.Policy_Updated);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>().Received()
|
||||
.UpsertAsync(policy);
|
||||
|
||||
Assert.True(policy.CreationDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
Assert.True(policy.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_ExistingPolicy_UpdateSingleOrg(
|
||||
[PolicyFixtures.Policy(PolicyType.TwoFactorAuthentication)] Policy policy, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
// If the policy that this is updating isn't enabled then do some work now that the current one is enabled
|
||||
|
||||
var org = new Organization
|
||||
{
|
||||
Id = policy.OrganizationId,
|
||||
UsePolicies = true,
|
||||
Name = "TEST",
|
||||
};
|
||||
|
||||
SetupOrg(sutProvider, policy.OrganizationId, org);
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByIdAsync(policy.Id)
|
||||
.Returns(new Policy
|
||||
{
|
||||
Id = policy.Id,
|
||||
Type = PolicyType.SingleOrg,
|
||||
Enabled = false,
|
||||
});
|
||||
|
||||
var orgUserDetail = new Core.Models.Data.Organizations.OrganizationUsers.OrganizationUserUserDetails
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Status = OrganizationUserStatusType.Accepted,
|
||||
Type = OrganizationUserType.User,
|
||||
// Needs to be different from what is passed in as the savingUserId to Sut.SaveAsync
|
||||
Email = "test@bitwarden.com",
|
||||
Name = "TEST",
|
||||
UserId = Guid.NewGuid(),
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyDetailsByOrganizationAsync(policy.OrganizationId)
|
||||
.Returns(new List<Core.Models.Data.Organizations.OrganizationUsers.OrganizationUserUserDetails>
|
||||
{
|
||||
orgUserDetail,
|
||||
});
|
||||
|
||||
var userService = Substitute.For<IUserService>();
|
||||
var organizationService = Substitute.For<IOrganizationService>();
|
||||
|
||||
userService.TwoFactorIsEnabledAsync(orgUserDetail)
|
||||
.Returns(false);
|
||||
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var savingUserId = Guid.NewGuid();
|
||||
|
||||
await sutProvider.Sut.SaveAsync(policy, userService, organizationService, savingUserId);
|
||||
|
||||
await sutProvider.GetDependency<IEventService>().Received()
|
||||
.LogPolicyEventAsync(policy, EventType.Policy_Updated);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyRepository>().Received()
|
||||
.UpsertAsync(policy);
|
||||
|
||||
Assert.True(policy.CreationDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
Assert.True(policy.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
private static void SetupOrg(SutProvider<PolicyService> sutProvider, Guid organizationId, Organization organization)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.GetByIdAsync(organizationId)
|
||||
.Returns(Task.FromResult(organization));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,40 +6,41 @@ using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class RelayPushNotificationServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly RelayPushNotificationService _sut;
|
||||
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
private readonly IDeviceRepository _deviceRepository;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ILogger<RelayPushNotificationService> _logger;
|
||||
|
||||
public RelayPushNotificationServiceTests()
|
||||
public class RelayPushNotificationServiceTests
|
||||
{
|
||||
_httpFactory = Substitute.For<IHttpClientFactory>();
|
||||
_deviceRepository = Substitute.For<IDeviceRepository>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
_httpContextAccessor = Substitute.For<IHttpContextAccessor>();
|
||||
_logger = Substitute.For<ILogger<RelayPushNotificationService>>();
|
||||
private readonly RelayPushNotificationService _sut;
|
||||
|
||||
_sut = new RelayPushNotificationService(
|
||||
_httpFactory,
|
||||
_deviceRepository,
|
||||
_globalSettings,
|
||||
_httpContextAccessor,
|
||||
_logger
|
||||
);
|
||||
}
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
private readonly IDeviceRepository _deviceRepository;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ILogger<RelayPushNotificationService> _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);
|
||||
public RelayPushNotificationServiceTests()
|
||||
{
|
||||
_httpFactory = Substitute.For<IHttpClientFactory>();
|
||||
_deviceRepository = Substitute.For<IDeviceRepository>();
|
||||
_globalSettings = new GlobalSettings();
|
||||
_httpContextAccessor = Substitute.For<IHttpContextAccessor>();
|
||||
_logger = Substitute.For<ILogger<RelayPushNotificationService>>();
|
||||
|
||||
_sut = new RelayPushNotificationService(
|
||||
_httpFactory,
|
||||
_deviceRepository,
|
||||
_globalSettings,
|
||||
_httpContextAccessor,
|
||||
_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,34 +4,35 @@ using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class RelayPushRegistrationServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly RelayPushRegistrationService _sut;
|
||||
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ILogger<RelayPushRegistrationService> _logger;
|
||||
|
||||
public RelayPushRegistrationServiceTests()
|
||||
public class RelayPushRegistrationServiceTests
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
_httpFactory = Substitute.For<IHttpClientFactory>();
|
||||
_logger = Substitute.For<ILogger<RelayPushRegistrationService>>();
|
||||
private readonly RelayPushRegistrationService _sut;
|
||||
|
||||
_sut = new RelayPushRegistrationService(
|
||||
_httpFactory,
|
||||
_globalSettings,
|
||||
_logger
|
||||
);
|
||||
}
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ILogger<RelayPushRegistrationService> _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);
|
||||
public RelayPushRegistrationServiceTests()
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
_httpFactory = Substitute.For<IHttpClientFactory>();
|
||||
_logger = Substitute.For<ILogger<RelayPushRegistrationService>>();
|
||||
|
||||
_sut = new RelayPushRegistrationService(
|
||||
_httpFactory,
|
||||
_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,26 +3,27 @@ using Bit.Core.Services;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class RepositoryEventWriteServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly RepositoryEventWriteService _sut;
|
||||
|
||||
private readonly IEventRepository _eventRepository;
|
||||
|
||||
public RepositoryEventWriteServiceTests()
|
||||
public class RepositoryEventWriteServiceTests
|
||||
{
|
||||
_eventRepository = Substitute.For<IEventRepository>();
|
||||
private readonly RepositoryEventWriteService _sut;
|
||||
|
||||
_sut = new RepositoryEventWriteService(_eventRepository);
|
||||
}
|
||||
private readonly IEventRepository _eventRepository;
|
||||
|
||||
// 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);
|
||||
public RepositoryEventWriteServiceTests()
|
||||
{
|
||||
_eventRepository = Substitute.For<IEventRepository>();
|
||||
|
||||
_sut = new RepositoryEventWriteService(_eventRepository);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,77 +8,78 @@ using SendGrid;
|
||||
using SendGrid.Helpers.Mail;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class SendGridMailDeliveryServiceTests : IDisposable
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
private readonly SendGridMailDeliveryService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IWebHostEnvironment _hostingEnvironment;
|
||||
private readonly ILogger<SendGridMailDeliveryService> _logger;
|
||||
private readonly ISendGridClient _sendGridClient;
|
||||
|
||||
public SendGridMailDeliveryServiceTests()
|
||||
public class SendGridMailDeliveryServiceTests : IDisposable
|
||||
{
|
||||
_globalSettings = new GlobalSettings
|
||||
private readonly SendGridMailDeliveryService _sut;
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IWebHostEnvironment _hostingEnvironment;
|
||||
private readonly ILogger<SendGridMailDeliveryService> _logger;
|
||||
private readonly ISendGridClient _sendGridClient;
|
||||
|
||||
public SendGridMailDeliveryServiceTests()
|
||||
{
|
||||
Mail =
|
||||
_globalSettings = new GlobalSettings
|
||||
{
|
||||
SendGridApiKey = "SendGridApiKey"
|
||||
}
|
||||
};
|
||||
Mail =
|
||||
{
|
||||
SendGridApiKey = "SendGridApiKey"
|
||||
}
|
||||
};
|
||||
|
||||
_hostingEnvironment = Substitute.For<IWebHostEnvironment>();
|
||||
_logger = Substitute.For<ILogger<SendGridMailDeliveryService>>();
|
||||
_sendGridClient = Substitute.For<ISendGridClient>();
|
||||
_hostingEnvironment = Substitute.For<IWebHostEnvironment>();
|
||||
_logger = Substitute.For<ILogger<SendGridMailDeliveryService>>();
|
||||
_sendGridClient = Substitute.For<ISendGridClient>();
|
||||
|
||||
_sut = new SendGridMailDeliveryService(
|
||||
_sendGridClient,
|
||||
_globalSettings,
|
||||
_hostingEnvironment,
|
||||
_logger
|
||||
);
|
||||
}
|
||||
_sut = new SendGridMailDeliveryService(
|
||||
_sendGridClient,
|
||||
_globalSettings,
|
||||
_hostingEnvironment,
|
||||
_logger
|
||||
);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_sut?.Dispose();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendEmailAsync_CallsSendEmailAsync_WhenMessageIsValid()
|
||||
{
|
||||
var mailMessage = new MailMessage
|
||||
public void Dispose()
|
||||
{
|
||||
ToEmails = new List<string> { "ToEmails" },
|
||||
BccEmails = new List<string> { "BccEmails" },
|
||||
Subject = "Subject",
|
||||
HtmlContent = "HtmlContent",
|
||||
TextContent = "TextContent",
|
||||
Category = "Category"
|
||||
};
|
||||
_sut?.Dispose();
|
||||
}
|
||||
|
||||
_sendGridClient.SendEmailAsync(Arg.Any<SendGridMessage>()).Returns(
|
||||
new Response(System.Net.HttpStatusCode.OK, null, null));
|
||||
await _sut.SendEmailAsync(mailMessage);
|
||||
|
||||
await _sendGridClient.Received(1).SendEmailAsync(
|
||||
Arg.Do<SendGridMessage>(msg =>
|
||||
[Fact]
|
||||
public async Task SendEmailAsync_CallsSendEmailAsync_WhenMessageIsValid()
|
||||
{
|
||||
var mailMessage = new MailMessage
|
||||
{
|
||||
msg.Received(1).AddTos(new List<EmailAddress> { new EmailAddress(mailMessage.ToEmails.First()) });
|
||||
msg.Received(1).AddBccs(new List<EmailAddress> { new EmailAddress(mailMessage.ToEmails.First()) });
|
||||
ToEmails = new List<string> { "ToEmails" },
|
||||
BccEmails = new List<string> { "BccEmails" },
|
||||
Subject = "Subject",
|
||||
HtmlContent = "HtmlContent",
|
||||
TextContent = "TextContent",
|
||||
Category = "Category"
|
||||
};
|
||||
|
||||
Assert.Equal(mailMessage.Subject, msg.Subject);
|
||||
Assert.Equal(mailMessage.HtmlContent, msg.HtmlContent);
|
||||
Assert.Equal(mailMessage.TextContent, msg.PlainTextContent);
|
||||
_sendGridClient.SendEmailAsync(Arg.Any<SendGridMessage>()).Returns(
|
||||
new Response(System.Net.HttpStatusCode.OK, null, null));
|
||||
await _sut.SendEmailAsync(mailMessage);
|
||||
|
||||
Assert.Contains("type:Cateogry", msg.Categories);
|
||||
Assert.Contains(msg.Categories, x => x.StartsWith("env:"));
|
||||
Assert.Contains(msg.Categories, x => x.StartsWith("sender:"));
|
||||
await _sendGridClient.Received(1).SendEmailAsync(
|
||||
Arg.Do<SendGridMessage>(msg =>
|
||||
{
|
||||
msg.Received(1).AddTos(new List<EmailAddress> { new EmailAddress(mailMessage.ToEmails.First()) });
|
||||
msg.Received(1).AddBccs(new List<EmailAddress> { new EmailAddress(mailMessage.ToEmails.First()) });
|
||||
|
||||
msg.Received(1).SetClickTracking(false, false);
|
||||
msg.Received(1).SetOpenTracking(false);
|
||||
}));
|
||||
Assert.Equal(mailMessage.Subject, msg.Subject);
|
||||
Assert.Equal(mailMessage.HtmlContent, msg.HtmlContent);
|
||||
Assert.Equal(mailMessage.TextContent, msg.PlainTextContent);
|
||||
|
||||
Assert.Contains("type:Cateogry", msg.Categories);
|
||||
Assert.Contains(msg.Categories, x => x.StartsWith("env:"));
|
||||
Assert.Contains(msg.Categories, x => x.StartsWith("sender:"));
|
||||
|
||||
msg.Received(1).SetClickTracking(false, false);
|
||||
msg.Received(1).SetOpenTracking(false);
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,308 +9,309 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class SsoConfigServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_ExistingItem_UpdatesRevisionDateOnly(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
public class SsoConfigServiceTests
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var ssoConfig = new SsoConfig
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_ExistingItem_UpdatesRevisionDateOnly(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
Id = 1,
|
||||
Data = "{}",
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
sutProvider.GetDependency<ISsoConfigRepository>()
|
||||
.UpsertAsync(ssoConfig).Returns(Task.CompletedTask);
|
||||
|
||||
await sutProvider.Sut.SaveAsync(ssoConfig, organization);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().Received()
|
||||
.UpsertAsync(ssoConfig);
|
||||
|
||||
Assert.Equal(utcNow.AddDays(-10), ssoConfig.CreationDate);
|
||||
Assert.True(ssoConfig.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_NewItem_UpdatesCreationAndRevisionDate(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
Id = default,
|
||||
Data = "{}",
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<ISsoConfigRepository>()
|
||||
.UpsertAsync(ssoConfig).Returns(Task.CompletedTask);
|
||||
|
||||
await sutProvider.Sut.SaveAsync(ssoConfig, organization);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().Received()
|
||||
.UpsertAsync(ssoConfig);
|
||||
|
||||
Assert.True(ssoConfig.CreationDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
Assert.True(ssoConfig.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_PreventDisablingKeyConnector(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var oldSsoConfig = new SsoConfig
|
||||
{
|
||||
Id = 1,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
var newSsoConfig = new SsoConfig
|
||||
{
|
||||
Id = 1,
|
||||
Data = "{}",
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow,
|
||||
};
|
||||
|
||||
var ssoConfigRepository = sutProvider.GetDependency<ISsoConfigRepository>();
|
||||
ssoConfigRepository.GetByOrganizationIdAsync(organization.Id).Returns(oldSsoConfig);
|
||||
ssoConfigRepository.UpsertAsync(newSsoConfig).Returns(Task.CompletedTask);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyDetailsByOrganizationAsync(organization.Id)
|
||||
.Returns(new[] { new OrganizationUserUserDetails { UsesKeyConnector = true } });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(newSsoConfig, organization));
|
||||
|
||||
Assert.Contains("Key Connector cannot be disabled at this moment.", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_AllowDisablingKeyConnectorWhenNoUserIsUsingIt(
|
||||
SutProvider<SsoConfigService> sutProvider, Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var oldSsoConfig = new SsoConfig
|
||||
{
|
||||
Id = 1,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
var newSsoConfig = new SsoConfig
|
||||
{
|
||||
Id = 1,
|
||||
Data = "{}",
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow,
|
||||
};
|
||||
|
||||
var ssoConfigRepository = sutProvider.GetDependency<ISsoConfigRepository>();
|
||||
ssoConfigRepository.GetByOrganizationIdAsync(organization.Id).Returns(oldSsoConfig);
|
||||
ssoConfigRepository.UpsertAsync(newSsoConfig).Returns(Task.CompletedTask);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyDetailsByOrganizationAsync(organization.Id)
|
||||
.Returns(new[] { new OrganizationUserUserDetails { UsesKeyConnector = false } });
|
||||
|
||||
await sutProvider.Sut.SaveAsync(newSsoConfig, organization);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_KeyConnector_SingleOrgNotEnabled_Throws(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(ssoConfig, organization));
|
||||
|
||||
Assert.Contains("Key Connector requires the Single Organization policy to be enabled.", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_KeyConnector_SsoPolicyNotEnabled_Throws(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>().GetByOrganizationIdTypeAsync(
|
||||
Arg.Any<Guid>(), Enums.PolicyType.SingleOrg).Returns(new Policy
|
||||
{
|
||||
Enabled = true
|
||||
});
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(ssoConfig, organization));
|
||||
|
||||
Assert.Contains("Key Connector requires the Single Sign-On Authentication policy to be enabled.", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_KeyConnector_SsoConfigNotEnabled_Throws(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = false,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>().GetByOrganizationIdTypeAsync(
|
||||
Arg.Any<Guid>(), Arg.Any<Enums.PolicyType>()).Returns(new Policy
|
||||
{
|
||||
Enabled = true
|
||||
});
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(ssoConfig, organization));
|
||||
|
||||
Assert.Contains("You must enable SSO to use Key Connector.", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_KeyConnector_KeyConnectorAbilityNotEnabled_Throws(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
organization.UseKeyConnector = false;
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>().GetByOrganizationIdTypeAsync(
|
||||
Arg.Any<Guid>(), Arg.Any<Enums.PolicyType>()).Returns(new Policy
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
Id = 1,
|
||||
Data = "{}",
|
||||
Enabled = true,
|
||||
});
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(ssoConfig, organization));
|
||||
sutProvider.GetDependency<ISsoConfigRepository>()
|
||||
.UpsertAsync(ssoConfig).Returns(Task.CompletedTask);
|
||||
|
||||
Assert.Contains("Organization cannot use Key Connector.", exception.Message);
|
||||
await sutProvider.Sut.SaveAsync(ssoConfig, organization);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().Received()
|
||||
.UpsertAsync(ssoConfig);
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_KeyConnector_Success(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
Assert.Equal(utcNow.AddDays(-10), ssoConfig.CreationDate);
|
||||
Assert.True(ssoConfig.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
organization.UseKeyConnector = true;
|
||||
var ssoConfig = new SsoConfig
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_NewItem_UpdatesCreationAndRevisionDate(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>().GetByOrganizationIdTypeAsync(
|
||||
Arg.Any<Guid>(), Arg.Any<Enums.PolicyType>()).Returns(new Policy
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
Id = default,
|
||||
Data = "{}",
|
||||
Enabled = true,
|
||||
});
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
await sutProvider.Sut.SaveAsync(ssoConfig, organization);
|
||||
sutProvider.GetDependency<ISsoConfigRepository>()
|
||||
.UpsertAsync(ssoConfig).Returns(Task.CompletedTask);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().ReceivedWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
await sutProvider.Sut.SaveAsync(ssoConfig, organization);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().Received()
|
||||
.UpsertAsync(ssoConfig);
|
||||
|
||||
Assert.True(ssoConfig.CreationDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
Assert.True(ssoConfig.RevisionDate - utcNow < TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_PreventDisablingKeyConnector(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var oldSsoConfig = new SsoConfig
|
||||
{
|
||||
Id = 1,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
var newSsoConfig = new SsoConfig
|
||||
{
|
||||
Id = 1,
|
||||
Data = "{}",
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow,
|
||||
};
|
||||
|
||||
var ssoConfigRepository = sutProvider.GetDependency<ISsoConfigRepository>();
|
||||
ssoConfigRepository.GetByOrganizationIdAsync(organization.Id).Returns(oldSsoConfig);
|
||||
ssoConfigRepository.UpsertAsync(newSsoConfig).Returns(Task.CompletedTask);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyDetailsByOrganizationAsync(organization.Id)
|
||||
.Returns(new[] { new OrganizationUserUserDetails { UsesKeyConnector = true } });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(newSsoConfig, organization));
|
||||
|
||||
Assert.Contains("Key Connector cannot be disabled at this moment.", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_AllowDisablingKeyConnectorWhenNoUserIsUsingIt(
|
||||
SutProvider<SsoConfigService> sutProvider, Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var oldSsoConfig = new SsoConfig
|
||||
{
|
||||
Id = 1,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
var newSsoConfig = new SsoConfig
|
||||
{
|
||||
Id = 1,
|
||||
Data = "{}",
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow,
|
||||
};
|
||||
|
||||
var ssoConfigRepository = sutProvider.GetDependency<ISsoConfigRepository>();
|
||||
ssoConfigRepository.GetByOrganizationIdAsync(organization.Id).Returns(oldSsoConfig);
|
||||
ssoConfigRepository.UpsertAsync(newSsoConfig).Returns(Task.CompletedTask);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyDetailsByOrganizationAsync(organization.Id)
|
||||
.Returns(new[] { new OrganizationUserUserDetails { UsesKeyConnector = false } });
|
||||
|
||||
await sutProvider.Sut.SaveAsync(newSsoConfig, organization);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_KeyConnector_SingleOrgNotEnabled_Throws(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(ssoConfig, organization));
|
||||
|
||||
Assert.Contains("Key Connector requires the Single Organization policy to be enabled.", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_KeyConnector_SsoPolicyNotEnabled_Throws(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>().GetByOrganizationIdTypeAsync(
|
||||
Arg.Any<Guid>(), Enums.PolicyType.SingleOrg).Returns(new Policy
|
||||
{
|
||||
Enabled = true
|
||||
});
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(ssoConfig, organization));
|
||||
|
||||
Assert.Contains("Key Connector requires the Single Sign-On Authentication policy to be enabled.", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_KeyConnector_SsoConfigNotEnabled_Throws(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = false,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>().GetByOrganizationIdTypeAsync(
|
||||
Arg.Any<Guid>(), Arg.Any<Enums.PolicyType>()).Returns(new Policy
|
||||
{
|
||||
Enabled = true
|
||||
});
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(ssoConfig, organization));
|
||||
|
||||
Assert.Contains("You must enable SSO to use Key Connector.", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_KeyConnector_KeyConnectorAbilityNotEnabled_Throws(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
organization.UseKeyConnector = false;
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>().GetByOrganizationIdTypeAsync(
|
||||
Arg.Any<Guid>(), Arg.Any<Enums.PolicyType>()).Returns(new Policy
|
||||
{
|
||||
Enabled = true,
|
||||
});
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(ssoConfig, organization));
|
||||
|
||||
Assert.Contains("Organization cannot use Key Connector.", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().DidNotReceiveWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SaveAsync_KeyConnector_Success(SutProvider<SsoConfigService> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
organization.UseKeyConnector = true;
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
Id = default,
|
||||
Data = new SsoConfigurationData
|
||||
{
|
||||
KeyConnectorEnabled = true,
|
||||
}.Serialize(),
|
||||
Enabled = true,
|
||||
OrganizationId = organization.Id,
|
||||
CreationDate = utcNow.AddDays(-10),
|
||||
RevisionDate = utcNow.AddDays(-10),
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>().GetByOrganizationIdTypeAsync(
|
||||
Arg.Any<Guid>(), Arg.Any<Enums.PolicyType>()).Returns(new Policy
|
||||
{
|
||||
Enabled = true,
|
||||
});
|
||||
|
||||
await sutProvider.Sut.SaveAsync(ssoConfig, organization);
|
||||
|
||||
await sutProvider.GetDependency<ISsoConfigRepository>().ReceivedWithAnyArgs()
|
||||
.UpsertAsync(default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,362 +12,363 @@ using NSubstitute;
|
||||
using Xunit;
|
||||
using PaymentMethodType = Bit.Core.Enums.PaymentMethodType;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class StripePaymentServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.BitPay)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.BitPay)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.Credit)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.WireTransfer)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.AppleInApp)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.GoogleInApp)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.Check)]
|
||||
public async void PurchaseOrganizationAsync_Invalid(PaymentMethodType paymentMethodType, SutProvider<StripePaymentService> sutProvider)
|
||||
public class StripePaymentServiceTests
|
||||
{
|
||||
var exception = await Assert.ThrowsAsync<GatewayException>(
|
||||
() => sutProvider.Sut.PurchaseOrganizationAsync(null, paymentMethodType, null, null, 0, 0, false, null));
|
||||
|
||||
Assert.Equal("Payment method is not supported at this time.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Stripe(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.BitPay)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.BitPay)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.Credit)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.WireTransfer)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.AppleInApp)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.GoogleInApp)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, PaymentMethodType.Check)]
|
||||
public async void PurchaseOrganizationAsync_Invalid(PaymentMethodType paymentMethodType, SutProvider<StripePaymentService> sutProvider)
|
||||
{
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
var exception = await Assert.ThrowsAsync<GatewayException>(
|
||||
() => sutProvider.Sut.PurchaseOrganizationAsync(null, paymentMethodType, null, null, 0, 0, false, null));
|
||||
|
||||
Assert.Equal("Payment method is not supported at this time.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Stripe(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
});
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Null(result);
|
||||
Assert.Equal(GatewayType.Stripe, organization.Gateway);
|
||||
Assert.Equal("C-1", organization.GatewayCustomerId);
|
||||
Assert.Equal("S-1", organization.GatewaySubscriptionId);
|
||||
Assert.True(organization.Enabled);
|
||||
Assert.Equal(DateTime.Today.AddDays(10), organization.ExpirationDate);
|
||||
|
||||
await stripeAdapter.Received().CustomerCreateAsync(Arg.Is<Stripe.CustomerCreateOptions>(c =>
|
||||
c.Description == organization.BusinessName &&
|
||||
c.Email == organization.BillingEmail &&
|
||||
c.Source == paymentToken &&
|
||||
c.PaymentMethod == null &&
|
||||
!c.Metadata.Any() &&
|
||||
c.InvoiceSettings.DefaultPaymentMethod == null &&
|
||||
c.Address.Country == taxInfo.BillingAddressCountry &&
|
||||
c.Address.PostalCode == taxInfo.BillingAddressPostalCode &&
|
||||
c.Address.Line1 == taxInfo.BillingAddressLine1 &&
|
||||
c.Address.Line2 == taxInfo.BillingAddressLine2 &&
|
||||
c.Address.City == taxInfo.BillingAddressCity &&
|
||||
c.Address.State == taxInfo.BillingAddressState &&
|
||||
c.TaxIdData == null
|
||||
));
|
||||
|
||||
await stripeAdapter.Received().SubscriptionCreateAsync(Arg.Is<Stripe.SubscriptionCreateOptions>(s =>
|
||||
s.Customer == "C-1" &&
|
||||
s.Expand[0] == "latest_invoice.payment_intent" &&
|
||||
s.Metadata[organization.GatewayIdField()] == organization.Id.ToString() &&
|
||||
s.Items.Count == 0
|
||||
));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Stripe_PM(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
paymentToken = "pm_" + paymentToken;
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
});
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Null(result);
|
||||
Assert.Equal(GatewayType.Stripe, organization.Gateway);
|
||||
Assert.Equal("C-1", organization.GatewayCustomerId);
|
||||
Assert.Equal("S-1", organization.GatewaySubscriptionId);
|
||||
Assert.True(organization.Enabled);
|
||||
Assert.Equal(DateTime.Today.AddDays(10), organization.ExpirationDate);
|
||||
|
||||
await stripeAdapter.Received().CustomerCreateAsync(Arg.Is<Stripe.CustomerCreateOptions>(c =>
|
||||
c.Description == organization.BusinessName &&
|
||||
c.Email == organization.BillingEmail &&
|
||||
c.Source == null &&
|
||||
c.PaymentMethod == paymentToken &&
|
||||
!c.Metadata.Any() &&
|
||||
c.InvoiceSettings.DefaultPaymentMethod == paymentToken &&
|
||||
c.Address.Country == taxInfo.BillingAddressCountry &&
|
||||
c.Address.PostalCode == taxInfo.BillingAddressPostalCode &&
|
||||
c.Address.Line1 == taxInfo.BillingAddressLine1 &&
|
||||
c.Address.Line2 == taxInfo.BillingAddressLine2 &&
|
||||
c.Address.City == taxInfo.BillingAddressCity &&
|
||||
c.Address.State == taxInfo.BillingAddressState &&
|
||||
c.TaxIdData == null
|
||||
));
|
||||
|
||||
await stripeAdapter.Received().SubscriptionCreateAsync(Arg.Is<Stripe.SubscriptionCreateOptions>(s =>
|
||||
s.Customer == "C-1" &&
|
||||
s.Expand[0] == "latest_invoice.payment_intent" &&
|
||||
s.Metadata[organization.GatewayIdField()] == organization.Id.ToString() &&
|
||||
s.Items.Count == 0
|
||||
));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Stripe_TaxRate(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
});
|
||||
sutProvider.GetDependency<ITaxRateRepository>().GetByLocationAsync(Arg.Is<TaxRate>(t =>
|
||||
t.Country == taxInfo.BillingAddressCountry && t.PostalCode == taxInfo.BillingAddressPostalCode))
|
||||
.Returns(new List<TaxRate> { new() { Id = "T-1" } });
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Null(result);
|
||||
|
||||
await stripeAdapter.Received().SubscriptionCreateAsync(Arg.Is<Stripe.SubscriptionCreateOptions>(s =>
|
||||
s.DefaultTaxRates.Count == 1 &&
|
||||
s.DefaultTaxRates[0] == "T-1"
|
||||
));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Stripe_Declined(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
paymentToken = "pm_" + paymentToken;
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
Status = "incomplete",
|
||||
LatestInvoice = new Stripe.Invoice
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
PaymentIntent = new Stripe.PaymentIntent
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
});
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Null(result);
|
||||
Assert.Equal(GatewayType.Stripe, organization.Gateway);
|
||||
Assert.Equal("C-1", organization.GatewayCustomerId);
|
||||
Assert.Equal("S-1", organization.GatewaySubscriptionId);
|
||||
Assert.True(organization.Enabled);
|
||||
Assert.Equal(DateTime.Today.AddDays(10), organization.ExpirationDate);
|
||||
|
||||
await stripeAdapter.Received().CustomerCreateAsync(Arg.Is<Stripe.CustomerCreateOptions>(c =>
|
||||
c.Description == organization.BusinessName &&
|
||||
c.Email == organization.BillingEmail &&
|
||||
c.Source == paymentToken &&
|
||||
c.PaymentMethod == null &&
|
||||
!c.Metadata.Any() &&
|
||||
c.InvoiceSettings.DefaultPaymentMethod == null &&
|
||||
c.Address.Country == taxInfo.BillingAddressCountry &&
|
||||
c.Address.PostalCode == taxInfo.BillingAddressPostalCode &&
|
||||
c.Address.Line1 == taxInfo.BillingAddressLine1 &&
|
||||
c.Address.Line2 == taxInfo.BillingAddressLine2 &&
|
||||
c.Address.City == taxInfo.BillingAddressCity &&
|
||||
c.Address.State == taxInfo.BillingAddressState &&
|
||||
c.TaxIdData == null
|
||||
));
|
||||
|
||||
await stripeAdapter.Received().SubscriptionCreateAsync(Arg.Is<Stripe.SubscriptionCreateOptions>(s =>
|
||||
s.Customer == "C-1" &&
|
||||
s.Expand[0] == "latest_invoice.payment_intent" &&
|
||||
s.Metadata[organization.GatewayIdField()] == organization.Id.ToString() &&
|
||||
s.Items.Count == 0
|
||||
));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Stripe_PM(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
paymentToken = "pm_" + paymentToken;
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
});
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Null(result);
|
||||
Assert.Equal(GatewayType.Stripe, organization.Gateway);
|
||||
Assert.Equal("C-1", organization.GatewayCustomerId);
|
||||
Assert.Equal("S-1", organization.GatewaySubscriptionId);
|
||||
Assert.True(organization.Enabled);
|
||||
Assert.Equal(DateTime.Today.AddDays(10), organization.ExpirationDate);
|
||||
|
||||
await stripeAdapter.Received().CustomerCreateAsync(Arg.Is<Stripe.CustomerCreateOptions>(c =>
|
||||
c.Description == organization.BusinessName &&
|
||||
c.Email == organization.BillingEmail &&
|
||||
c.Source == null &&
|
||||
c.PaymentMethod == paymentToken &&
|
||||
!c.Metadata.Any() &&
|
||||
c.InvoiceSettings.DefaultPaymentMethod == paymentToken &&
|
||||
c.Address.Country == taxInfo.BillingAddressCountry &&
|
||||
c.Address.PostalCode == taxInfo.BillingAddressPostalCode &&
|
||||
c.Address.Line1 == taxInfo.BillingAddressLine1 &&
|
||||
c.Address.Line2 == taxInfo.BillingAddressLine2 &&
|
||||
c.Address.City == taxInfo.BillingAddressCity &&
|
||||
c.Address.State == taxInfo.BillingAddressState &&
|
||||
c.TaxIdData == null
|
||||
));
|
||||
|
||||
await stripeAdapter.Received().SubscriptionCreateAsync(Arg.Is<Stripe.SubscriptionCreateOptions>(s =>
|
||||
s.Customer == "C-1" &&
|
||||
s.Expand[0] == "latest_invoice.payment_intent" &&
|
||||
s.Metadata[organization.GatewayIdField()] == organization.Id.ToString() &&
|
||||
s.Items.Count == 0
|
||||
));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Stripe_TaxRate(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
});
|
||||
sutProvider.GetDependency<ITaxRateRepository>().GetByLocationAsync(Arg.Is<TaxRate>(t =>
|
||||
t.Country == taxInfo.BillingAddressCountry && t.PostalCode == taxInfo.BillingAddressPostalCode))
|
||||
.Returns(new List<TaxRate> { new() { Id = "T-1" } });
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Null(result);
|
||||
|
||||
await stripeAdapter.Received().SubscriptionCreateAsync(Arg.Is<Stripe.SubscriptionCreateOptions>(s =>
|
||||
s.DefaultTaxRates.Count == 1 &&
|
||||
s.DefaultTaxRates[0] == "T-1"
|
||||
));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Stripe_Declined(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
paymentToken = "pm_" + paymentToken;
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
Status = "incomplete",
|
||||
LatestInvoice = new Stripe.Invoice
|
||||
{
|
||||
Status = "requires_payment_method",
|
||||
PaymentIntent = new Stripe.PaymentIntent
|
||||
{
|
||||
Status = "requires_payment_method",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
var exception = await Assert.ThrowsAsync<GatewayException>(
|
||||
() => sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo));
|
||||
var exception = await Assert.ThrowsAsync<GatewayException>(
|
||||
() => sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo));
|
||||
|
||||
Assert.Equal("Payment method was declined.", exception.Message);
|
||||
Assert.Equal("Payment method was declined.", exception.Message);
|
||||
|
||||
await stripeAdapter.Received(1).CustomerDeleteAsync("C-1");
|
||||
}
|
||||
await stripeAdapter.Received(1).CustomerDeleteAsync("C-1");
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Stripe_RequiresAction(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Stripe_RequiresAction(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
Status = "incomplete",
|
||||
LatestInvoice = new Stripe.Invoice
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
PaymentIntent = new Stripe.PaymentIntent
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
Status = "incomplete",
|
||||
LatestInvoice = new Stripe.Invoice
|
||||
{
|
||||
Status = "requires_action",
|
||||
ClientSecret = "clientSecret",
|
||||
PaymentIntent = new Stripe.PaymentIntent
|
||||
{
|
||||
Status = "requires_action",
|
||||
ClientSecret = "clientSecret",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.Card, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Equal("clientSecret", result);
|
||||
Assert.False(organization.Enabled);
|
||||
}
|
||||
Assert.Equal("clientSecret", result);
|
||||
Assert.False(organization.Enabled);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Paypal(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Paypal(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
});
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
|
||||
var customer = Substitute.For<Customer>();
|
||||
customer.Id.ReturnsForAnyArgs("Braintree-Id");
|
||||
customer.PaymentMethods.ReturnsForAnyArgs(new[] { Substitute.For<PaymentMethod>() });
|
||||
var customerResult = Substitute.For<Result<Customer>>();
|
||||
customerResult.IsSuccess().Returns(true);
|
||||
customerResult.Target.ReturnsForAnyArgs(customer);
|
||||
|
||||
var braintreeGateway = sutProvider.GetDependency<IBraintreeGateway>();
|
||||
braintreeGateway.Customer.CreateAsync(default).ReturnsForAnyArgs(customerResult);
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Null(result);
|
||||
Assert.Equal(GatewayType.Stripe, organization.Gateway);
|
||||
Assert.Equal("C-1", organization.GatewayCustomerId);
|
||||
Assert.Equal("S-1", organization.GatewaySubscriptionId);
|
||||
Assert.True(organization.Enabled);
|
||||
Assert.Equal(DateTime.Today.AddDays(10), organization.ExpirationDate);
|
||||
|
||||
await stripeAdapter.Received().CustomerCreateAsync(Arg.Is<Stripe.CustomerCreateOptions>(c =>
|
||||
c.Description == organization.BusinessName &&
|
||||
c.Email == organization.BillingEmail &&
|
||||
c.PaymentMethod == null &&
|
||||
c.Metadata.Count == 1 &&
|
||||
c.Metadata["btCustomerId"] == "Braintree-Id" &&
|
||||
c.InvoiceSettings.DefaultPaymentMethod == null &&
|
||||
c.Address.Country == taxInfo.BillingAddressCountry &&
|
||||
c.Address.PostalCode == taxInfo.BillingAddressPostalCode &&
|
||||
c.Address.Line1 == taxInfo.BillingAddressLine1 &&
|
||||
c.Address.Line2 == taxInfo.BillingAddressLine2 &&
|
||||
c.Address.City == taxInfo.BillingAddressCity &&
|
||||
c.Address.State == taxInfo.BillingAddressState &&
|
||||
c.TaxIdData == null
|
||||
));
|
||||
|
||||
await stripeAdapter.Received().SubscriptionCreateAsync(Arg.Is<Stripe.SubscriptionCreateOptions>(s =>
|
||||
s.Customer == "C-1" &&
|
||||
s.Expand[0] == "latest_invoice.payment_intent" &&
|
||||
s.Metadata[organization.GatewayIdField()] == organization.Id.ToString() &&
|
||||
s.Items.Count == 0
|
||||
));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Paypal_FailedCreate(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
|
||||
var customerResult = Substitute.For<Result<Customer>>();
|
||||
customerResult.IsSuccess().Returns(false);
|
||||
|
||||
var braintreeGateway = sutProvider.GetDependency<IBraintreeGateway>();
|
||||
braintreeGateway.Customer.CreateAsync(default).ReturnsForAnyArgs(customerResult);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<GatewayException>(
|
||||
() => sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plan, 0, 0, false, taxInfo));
|
||||
|
||||
Assert.Equal("Failed to create PayPal customer record.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_PayPal_Declined(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
paymentToken = "pm_" + paymentToken;
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
Status = "incomplete",
|
||||
LatestInvoice = new Stripe.Invoice
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
PaymentIntent = new Stripe.PaymentIntent
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
});
|
||||
|
||||
var customer = Substitute.For<Customer>();
|
||||
customer.Id.ReturnsForAnyArgs("Braintree-Id");
|
||||
customer.PaymentMethods.ReturnsForAnyArgs(new[] { Substitute.For<PaymentMethod>() });
|
||||
var customerResult = Substitute.For<Result<Customer>>();
|
||||
customerResult.IsSuccess().Returns(true);
|
||||
customerResult.Target.ReturnsForAnyArgs(customer);
|
||||
|
||||
var braintreeGateway = sutProvider.GetDependency<IBraintreeGateway>();
|
||||
braintreeGateway.Customer.CreateAsync(default).ReturnsForAnyArgs(customerResult);
|
||||
|
||||
var result = await sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Null(result);
|
||||
Assert.Equal(GatewayType.Stripe, organization.Gateway);
|
||||
Assert.Equal("C-1", organization.GatewayCustomerId);
|
||||
Assert.Equal("S-1", organization.GatewaySubscriptionId);
|
||||
Assert.True(organization.Enabled);
|
||||
Assert.Equal(DateTime.Today.AddDays(10), organization.ExpirationDate);
|
||||
|
||||
await stripeAdapter.Received().CustomerCreateAsync(Arg.Is<Stripe.CustomerCreateOptions>(c =>
|
||||
c.Description == organization.BusinessName &&
|
||||
c.Email == organization.BillingEmail &&
|
||||
c.PaymentMethod == null &&
|
||||
c.Metadata.Count == 1 &&
|
||||
c.Metadata["btCustomerId"] == "Braintree-Id" &&
|
||||
c.InvoiceSettings.DefaultPaymentMethod == null &&
|
||||
c.Address.Country == taxInfo.BillingAddressCountry &&
|
||||
c.Address.PostalCode == taxInfo.BillingAddressPostalCode &&
|
||||
c.Address.Line1 == taxInfo.BillingAddressLine1 &&
|
||||
c.Address.Line2 == taxInfo.BillingAddressLine2 &&
|
||||
c.Address.City == taxInfo.BillingAddressCity &&
|
||||
c.Address.State == taxInfo.BillingAddressState &&
|
||||
c.TaxIdData == null
|
||||
));
|
||||
|
||||
await stripeAdapter.Received().SubscriptionCreateAsync(Arg.Is<Stripe.SubscriptionCreateOptions>(s =>
|
||||
s.Customer == "C-1" &&
|
||||
s.Expand[0] == "latest_invoice.payment_intent" &&
|
||||
s.Metadata[organization.GatewayIdField()] == organization.Id.ToString() &&
|
||||
s.Items.Count == 0
|
||||
));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_Paypal_FailedCreate(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
|
||||
var customerResult = Substitute.For<Result<Customer>>();
|
||||
customerResult.IsSuccess().Returns(false);
|
||||
|
||||
var braintreeGateway = sutProvider.GetDependency<IBraintreeGateway>();
|
||||
braintreeGateway.Customer.CreateAsync(default).ReturnsForAnyArgs(customerResult);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<GatewayException>(
|
||||
() => sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plan, 0, 0, false, taxInfo));
|
||||
|
||||
Assert.Equal("Failed to create PayPal customer record.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void PurchaseOrganizationAsync_PayPal_Declined(SutProvider<StripePaymentService> sutProvider, Organization organization, string paymentToken, TaxInfo taxInfo)
|
||||
{
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
paymentToken = "pm_" + paymentToken;
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerCreateAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
Id = "C-1",
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription
|
||||
{
|
||||
Id = "S-1",
|
||||
CurrentPeriodEnd = DateTime.Today.AddDays(10),
|
||||
Status = "incomplete",
|
||||
LatestInvoice = new Stripe.Invoice
|
||||
{
|
||||
Status = "requires_payment_method",
|
||||
PaymentIntent = new Stripe.PaymentIntent
|
||||
{
|
||||
Status = "requires_payment_method",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
var customer = Substitute.For<Customer>();
|
||||
customer.Id.ReturnsForAnyArgs("Braintree-Id");
|
||||
customer.PaymentMethods.ReturnsForAnyArgs(new[] { Substitute.For<PaymentMethod>() });
|
||||
var customerResult = Substitute.For<Result<Customer>>();
|
||||
customerResult.IsSuccess().Returns(true);
|
||||
customerResult.Target.ReturnsForAnyArgs(customer);
|
||||
var customer = Substitute.For<Customer>();
|
||||
customer.Id.ReturnsForAnyArgs("Braintree-Id");
|
||||
customer.PaymentMethods.ReturnsForAnyArgs(new[] { Substitute.For<PaymentMethod>() });
|
||||
var customerResult = Substitute.For<Result<Customer>>();
|
||||
customerResult.IsSuccess().Returns(true);
|
||||
customerResult.Target.ReturnsForAnyArgs(customer);
|
||||
|
||||
var braintreeGateway = sutProvider.GetDependency<IBraintreeGateway>();
|
||||
braintreeGateway.Customer.CreateAsync(default).ReturnsForAnyArgs(customerResult);
|
||||
var braintreeGateway = sutProvider.GetDependency<IBraintreeGateway>();
|
||||
braintreeGateway.Customer.CreateAsync(default).ReturnsForAnyArgs(customerResult);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<GatewayException>(
|
||||
() => sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plan, 0, 0, false, taxInfo));
|
||||
var exception = await Assert.ThrowsAsync<GatewayException>(
|
||||
() => sutProvider.Sut.PurchaseOrganizationAsync(organization, PaymentMethodType.PayPal, paymentToken, plan, 0, 0, false, taxInfo));
|
||||
|
||||
Assert.Equal("Payment method was declined.", exception.Message);
|
||||
Assert.Equal("Payment method was declined.", exception.Message);
|
||||
|
||||
await stripeAdapter.Received(1).CustomerDeleteAsync("C-1");
|
||||
await braintreeGateway.Customer.Received(1).DeleteAsync("Braintree-Id");
|
||||
}
|
||||
await stripeAdapter.Received(1).CustomerDeleteAsync("C-1");
|
||||
await braintreeGateway.Customer.Received(1).DeleteAsync("Braintree-Id");
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void UpgradeFreeOrganizationAsync_Success(SutProvider<StripePaymentService> sutProvider,
|
||||
Organization organization, TaxInfo taxInfo)
|
||||
{
|
||||
organization.GatewaySubscriptionId = null;
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerGetAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void UpgradeFreeOrganizationAsync_Success(SutProvider<StripePaymentService> sutProvider,
|
||||
Organization organization, TaxInfo taxInfo)
|
||||
{
|
||||
Id = "C-1",
|
||||
Metadata = new Dictionary<string, string>
|
||||
organization.GatewaySubscriptionId = null;
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
stripeAdapter.CustomerGetAsync(default).ReturnsForAnyArgs(new Stripe.Customer
|
||||
{
|
||||
{ "btCustomerId", "B-123" },
|
||||
}
|
||||
});
|
||||
stripeAdapter.InvoiceUpcomingAsync(default).ReturnsForAnyArgs(new Stripe.Invoice
|
||||
{
|
||||
PaymentIntent = new Stripe.PaymentIntent { Status = "requires_payment_method", },
|
||||
AmountDue = 0
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription { });
|
||||
Id = "C-1",
|
||||
Metadata = new Dictionary<string, string>
|
||||
{
|
||||
{ "btCustomerId", "B-123" },
|
||||
}
|
||||
});
|
||||
stripeAdapter.InvoiceUpcomingAsync(default).ReturnsForAnyArgs(new Stripe.Invoice
|
||||
{
|
||||
PaymentIntent = new Stripe.PaymentIntent { Status = "requires_payment_method", },
|
||||
AmountDue = 0
|
||||
});
|
||||
stripeAdapter.SubscriptionCreateAsync(default).ReturnsForAnyArgs(new Stripe.Subscription { });
|
||||
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
var result = await sutProvider.Sut.UpgradeFreeOrganizationAsync(organization, plan, 0, 0, false, taxInfo);
|
||||
var plan = StaticStore.Plans.First(p => p.Type == PlanType.EnterpriseAnnually);
|
||||
var result = await sutProvider.Sut.UpgradeFreeOrganizationAsync(organization, plan, 0, 0, false, taxInfo);
|
||||
|
||||
Assert.Null(result);
|
||||
Assert.Null(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,375 +14,376 @@ using NSubstitute;
|
||||
using NSubstitute.ReceivedExtensions;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
public class UserServiceTests
|
||||
namespace Bit.Core.Test.Services
|
||||
{
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task UpdateLicenseAsync_Success(SutProvider<UserService> sutProvider,
|
||||
User user, UserLicense userLicense)
|
||||
public class UserServiceTests
|
||||
{
|
||||
using var tempDir = new TempDirectory();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
userLicense.Issued = now.AddDays(-10);
|
||||
userLicense.Expires = now.AddDays(10);
|
||||
userLicense.Version = 1;
|
||||
userLicense.Premium = true;
|
||||
|
||||
user.EmailVerified = true;
|
||||
user.Email = userLicense.Email;
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().SelfHosted = true;
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().LicenseDirectory = tempDir.Directory;
|
||||
sutProvider.GetDependency<ILicensingService>()
|
||||
.VerifyLicense(userLicense)
|
||||
.Returns(true);
|
||||
|
||||
await sutProvider.Sut.UpdateLicenseAsync(user, userLicense);
|
||||
|
||||
var filePath = Path.Combine(tempDir.Directory, "user", $"{user.Id}.json");
|
||||
Assert.True(File.Exists(filePath));
|
||||
var document = JsonDocument.Parse(File.OpenRead(filePath));
|
||||
var root = document.RootElement;
|
||||
Assert.Equal(JsonValueKind.Object, root.ValueKind);
|
||||
// Sort of a lazy way to test that it is indented but not sure of a better way
|
||||
Assert.Contains('\n', root.GetRawText());
|
||||
AssertHelper.AssertJsonProperty(root, "LicenseKey", JsonValueKind.String);
|
||||
AssertHelper.AssertJsonProperty(root, "Id", JsonValueKind.String);
|
||||
AssertHelper.AssertJsonProperty(root, "Premium", JsonValueKind.True);
|
||||
var versionProp = AssertHelper.AssertJsonProperty(root, "Version", JsonValueKind.Number);
|
||||
Assert.Equal(1, versionProp.GetInt32());
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SendTwoFactorEmailAsync_Success(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
var email = user.Email.ToLowerInvariant();
|
||||
var token = "thisisatokentocompare";
|
||||
|
||||
var userTwoFactorTokenProvider = Substitute.For<IUserTwoFactorTokenProvider<User>>();
|
||||
userTwoFactorTokenProvider
|
||||
.CanGenerateTwoFactorTokenAsync(Arg.Any<UserManager<User>>(), user)
|
||||
.Returns(Task.FromResult(true));
|
||||
userTwoFactorTokenProvider
|
||||
.GenerateAsync("2faEmail:" + email, Arg.Any<UserManager<User>>(), user)
|
||||
.Returns(Task.FromResult(token));
|
||||
|
||||
sutProvider.Sut.RegisterTokenProvider("Email", userTwoFactorTokenProvider);
|
||||
|
||||
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task UpdateLicenseAsync_Success(SutProvider<UserService> sutProvider,
|
||||
User user, UserLicense userLicense)
|
||||
{
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
{
|
||||
MetaData = new Dictionary<string, object> { ["Email"] = email },
|
||||
Enabled = true
|
||||
}
|
||||
});
|
||||
await sutProvider.Sut.SendTwoFactorEmailAsync(user);
|
||||
using var tempDir = new TempDirectory();
|
||||
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.Received(1)
|
||||
.SendTwoFactorEmailAsync(email, token);
|
||||
}
|
||||
var now = DateTime.UtcNow;
|
||||
userLicense.Issued = now.AddDays(-10);
|
||||
userLicense.Expires = now.AddDays(10);
|
||||
userLicense.Version = 1;
|
||||
userLicense.Premium = true;
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SendTwoFactorEmailBecauseNewDeviceLoginAsync_Success(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
var email = user.Email.ToLowerInvariant();
|
||||
var token = "thisisatokentocompare";
|
||||
user.EmailVerified = true;
|
||||
user.Email = userLicense.Email;
|
||||
|
||||
var userTwoFactorTokenProvider = Substitute.For<IUserTwoFactorTokenProvider<User>>();
|
||||
userTwoFactorTokenProvider
|
||||
.CanGenerateTwoFactorTokenAsync(Arg.Any<UserManager<User>>(), user)
|
||||
.Returns(Task.FromResult(true));
|
||||
userTwoFactorTokenProvider
|
||||
.GenerateAsync("2faEmail:" + email, Arg.Any<UserManager<User>>(), user)
|
||||
.Returns(Task.FromResult(token));
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().SelfHosted = true;
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().LicenseDirectory = tempDir.Directory;
|
||||
sutProvider.GetDependency<ILicensingService>()
|
||||
.VerifyLicense(userLicense)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.Sut.RegisterTokenProvider("Email", userTwoFactorTokenProvider);
|
||||
await sutProvider.Sut.UpdateLicenseAsync(user, userLicense);
|
||||
|
||||
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
var filePath = Path.Combine(tempDir.Directory, "user", $"{user.Id}.json");
|
||||
Assert.True(File.Exists(filePath));
|
||||
var document = JsonDocument.Parse(File.OpenRead(filePath));
|
||||
var root = document.RootElement;
|
||||
Assert.Equal(JsonValueKind.Object, root.ValueKind);
|
||||
// Sort of a lazy way to test that it is indented but not sure of a better way
|
||||
Assert.Contains('\n', root.GetRawText());
|
||||
AssertHelper.AssertJsonProperty(root, "LicenseKey", JsonValueKind.String);
|
||||
AssertHelper.AssertJsonProperty(root, "Id", JsonValueKind.String);
|
||||
AssertHelper.AssertJsonProperty(root, "Premium", JsonValueKind.True);
|
||||
var versionProp = AssertHelper.AssertJsonProperty(root, "Version", JsonValueKind.Number);
|
||||
Assert.Equal(1, versionProp.GetInt32());
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SendTwoFactorEmailAsync_Success(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
var email = user.Email.ToLowerInvariant();
|
||||
var token = "thisisatokentocompare";
|
||||
|
||||
var userTwoFactorTokenProvider = Substitute.For<IUserTwoFactorTokenProvider<User>>();
|
||||
userTwoFactorTokenProvider
|
||||
.CanGenerateTwoFactorTokenAsync(Arg.Any<UserManager<User>>(), user)
|
||||
.Returns(Task.FromResult(true));
|
||||
userTwoFactorTokenProvider
|
||||
.GenerateAsync("2faEmail:" + email, Arg.Any<UserManager<User>>(), user)
|
||||
.Returns(Task.FromResult(token));
|
||||
|
||||
sutProvider.Sut.RegisterTokenProvider("Email", userTwoFactorTokenProvider);
|
||||
|
||||
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
{
|
||||
MetaData = new Dictionary<string, object> { ["Email"] = email },
|
||||
Enabled = true
|
||||
}
|
||||
});
|
||||
await sutProvider.Sut.SendTwoFactorEmailAsync(user, true);
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
{
|
||||
MetaData = new Dictionary<string, object> { ["Email"] = email },
|
||||
Enabled = true
|
||||
}
|
||||
});
|
||||
await sutProvider.Sut.SendTwoFactorEmailAsync(user);
|
||||
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.Received(1)
|
||||
.SendNewDeviceLoginTwoFactorEmailAsync(email, token);
|
||||
}
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.Received(1)
|
||||
.SendTwoFactorEmailAsync(email, token);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SendTwoFactorEmailAsync_ExceptionBecauseNoProviderOnUser(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.TwoFactorProviders = null;
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("No email.", () => sutProvider.Sut.SendTwoFactorEmailAsync(user));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SendTwoFactorEmailAsync_ExceptionBecauseNoProviderMetadataOnUser(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SendTwoFactorEmailBecauseNewDeviceLoginAsync_Success(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
var email = user.Email.ToLowerInvariant();
|
||||
var token = "thisisatokentocompare";
|
||||
|
||||
var userTwoFactorTokenProvider = Substitute.For<IUserTwoFactorTokenProvider<User>>();
|
||||
userTwoFactorTokenProvider
|
||||
.CanGenerateTwoFactorTokenAsync(Arg.Any<UserManager<User>>(), user)
|
||||
.Returns(Task.FromResult(true));
|
||||
userTwoFactorTokenProvider
|
||||
.GenerateAsync("2faEmail:" + email, Arg.Any<UserManager<User>>(), user)
|
||||
.Returns(Task.FromResult(token));
|
||||
|
||||
sutProvider.Sut.RegisterTokenProvider("Email", userTwoFactorTokenProvider);
|
||||
|
||||
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
{
|
||||
MetaData = null,
|
||||
Enabled = true
|
||||
}
|
||||
});
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
{
|
||||
MetaData = new Dictionary<string, object> { ["Email"] = email },
|
||||
Enabled = true
|
||||
}
|
||||
});
|
||||
await sutProvider.Sut.SendTwoFactorEmailAsync(user, true);
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("No email.", () => sutProvider.Sut.SendTwoFactorEmailAsync(user));
|
||||
}
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.Received(1)
|
||||
.SendNewDeviceLoginTwoFactorEmailAsync(email, token);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SendTwoFactorEmailAsync_ExceptionBecauseNoProviderEmailMetadataOnUser(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SendTwoFactorEmailAsync_ExceptionBecauseNoProviderOnUser(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
{
|
||||
MetaData = new Dictionary<string, object> { ["qweqwe"] = user.Email.ToLowerInvariant() },
|
||||
Enabled = true
|
||||
}
|
||||
});
|
||||
user.TwoFactorProviders = null;
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("No email.", () => sutProvider.Sut.SendTwoFactorEmailAsync(user));
|
||||
}
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("No email.", () => sutProvider.Sut.SendTwoFactorEmailAsync(user));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsTrue(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
user.UnknownDeviceVerificationEnabled = true;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>
|
||||
{
|
||||
new Device { Identifier = deviceIdInRepo }
|
||||
}));
|
||||
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
|
||||
|
||||
Assert.True(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_GranType_Is_AuthorizationCode(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>
|
||||
{
|
||||
new Device { Identifier = deviceIdInRepo }
|
||||
}));
|
||||
|
||||
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "authorization_code"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_Email_Is_Not_Verified(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = false;
|
||||
user.TwoFactorProviders = null;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>
|
||||
{
|
||||
new Device { Identifier = deviceIdInRepo }
|
||||
}));
|
||||
|
||||
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_Is_The_First_Device(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>()));
|
||||
|
||||
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_DeviceId_Is_Already_In_Repo(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>
|
||||
{
|
||||
new Device { Identifier = deviceIdToCheck }
|
||||
}));
|
||||
|
||||
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_GlobalSettings_2FA_EmailOnNewDeviceLogin_Is_Disabled(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>
|
||||
{
|
||||
new Device { Identifier = deviceIdInRepo }
|
||||
}));
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(false);
|
||||
|
||||
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_UnknownDeviceVerification_Is_Disabled(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
user.UnknownDeviceVerificationEnabled = false;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>
|
||||
{
|
||||
new Device { Identifier = deviceIdInRepo }
|
||||
}));
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
|
||||
|
||||
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public void CanEditDeviceVerificationSettings_ReturnsTrue(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
|
||||
|
||||
Assert.True(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public void CanEditDeviceVerificationSettings_ReturnsFalse_When_GlobalSettings_2FA_EmailOnNewDeviceLogin_Is_Disabled(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(false);
|
||||
|
||||
Assert.False(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public void CanEditDeviceVerificationSettings_ReturnsFalse_When_Email_Is_Not_Verified(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = false;
|
||||
user.TwoFactorProviders = null;
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
|
||||
|
||||
Assert.False(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public void CanEditDeviceVerificationSettings_ReturnsFalse_When_User_Uses_Key_Connector(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
user.UsesKeyConnector = true;
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
|
||||
|
||||
Assert.False(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public void CanEditDeviceVerificationSettings_ReturnsFalse_When_User_Has_A_2FA_Already_Set_Up(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SendTwoFactorEmailAsync_ExceptionBecauseNoProviderMetadataOnUser(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
{
|
||||
MetaData = new Dictionary<string, object> { ["Email"] = "asdfasf" },
|
||||
Enabled = true
|
||||
}
|
||||
});
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
{
|
||||
MetaData = null,
|
||||
Enabled = true
|
||||
}
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("No email.", () => sutProvider.Sut.SendTwoFactorEmailAsync(user));
|
||||
}
|
||||
|
||||
Assert.False(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
|
||||
}
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task SendTwoFactorEmailAsync_ExceptionBecauseNoProviderEmailMetadataOnUser(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
{
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
{
|
||||
MetaData = new Dictionary<string, object> { ["qweqwe"] = user.Email.ToLowerInvariant() },
|
||||
Enabled = true
|
||||
}
|
||||
});
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void HasPremiumFromOrganization_Returns_False_If_No_Orgs(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyByUserAsync(user.Id).Returns(new List<OrganizationUser>());
|
||||
Assert.False(await sutProvider.Sut.HasPremiumFromOrganization(user));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("No email.", () => sutProvider.Sut.SendTwoFactorEmailAsync(user));
|
||||
}
|
||||
|
||||
}
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsTrue(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
user.UnknownDeviceVerificationEnabled = true;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
|
||||
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, false, true)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, true, false)]
|
||||
public async void HasPremiumFromOrganization_Returns_False_If_Org_Not_Eligible(bool orgEnabled, bool orgUsersGetPremium, SutProvider<UserService> sutProvider, User user, OrganizationUser orgUser, Organization organization)
|
||||
{
|
||||
orgUser.OrganizationId = organization.Id;
|
||||
organization.Enabled = orgEnabled;
|
||||
organization.UsersGetPremium = orgUsersGetPremium;
|
||||
var orgAbilities = new Dictionary<Guid, OrganizationAbility>() { { organization.Id, new OrganizationAbility(organization) } };
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>
|
||||
{
|
||||
new Device { Identifier = deviceIdInRepo }
|
||||
}));
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyByUserAsync(user.Id).Returns(new List<OrganizationUser>() { orgUser });
|
||||
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilitiesAsync().Returns(orgAbilities);
|
||||
|
||||
Assert.False(await sutProvider.Sut.HasPremiumFromOrganization(user));
|
||||
}
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void HasPremiumFromOrganization_Returns_True_If_Org_Eligible(SutProvider<UserService> sutProvider, User user, OrganizationUser orgUser, Organization organization)
|
||||
{
|
||||
orgUser.OrganizationId = organization.Id;
|
||||
organization.Enabled = true;
|
||||
organization.UsersGetPremium = true;
|
||||
var orgAbilities = new Dictionary<Guid, OrganizationAbility>() { { organization.Id, new OrganizationAbility(organization) } };
|
||||
Assert.True(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||
}
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyByUserAsync(user.Id).Returns(new List<OrganizationUser>() { orgUser });
|
||||
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilitiesAsync().Returns(orgAbilities);
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_GranType_Is_AuthorizationCode(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
|
||||
|
||||
Assert.True(await sutProvider.Sut.HasPremiumFromOrganization(user));
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>
|
||||
{
|
||||
new Device { Identifier = deviceIdInRepo }
|
||||
}));
|
||||
|
||||
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "authorization_code"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_Email_Is_Not_Verified(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = false;
|
||||
user.TwoFactorProviders = null;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>
|
||||
{
|
||||
new Device { Identifier = deviceIdInRepo }
|
||||
}));
|
||||
|
||||
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_Is_The_First_Device(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>()));
|
||||
|
||||
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_DeviceId_Is_Already_In_Repo(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>
|
||||
{
|
||||
new Device { Identifier = deviceIdToCheck }
|
||||
}));
|
||||
|
||||
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_GlobalSettings_2FA_EmailOnNewDeviceLogin_Is_Disabled(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>
|
||||
{
|
||||
new Device { Identifier = deviceIdInRepo }
|
||||
}));
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(false);
|
||||
|
||||
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_UnknownDeviceVerification_Is_Disabled(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
user.UnknownDeviceVerificationEnabled = false;
|
||||
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
|
||||
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>
|
||||
{
|
||||
new Device { Identifier = deviceIdInRepo }
|
||||
}));
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
|
||||
|
||||
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public void CanEditDeviceVerificationSettings_ReturnsTrue(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
|
||||
|
||||
Assert.True(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public void CanEditDeviceVerificationSettings_ReturnsFalse_When_GlobalSettings_2FA_EmailOnNewDeviceLogin_Is_Disabled(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(false);
|
||||
|
||||
Assert.False(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public void CanEditDeviceVerificationSettings_ReturnsFalse_When_Email_Is_Not_Verified(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = false;
|
||||
user.TwoFactorProviders = null;
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
|
||||
|
||||
Assert.False(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public void CanEditDeviceVerificationSettings_ReturnsFalse_When_User_Uses_Key_Connector(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.TwoFactorProviders = null;
|
||||
user.UsesKeyConnector = true;
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
|
||||
|
||||
Assert.False(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public void CanEditDeviceVerificationSettings_ReturnsFalse_When_User_Has_A_2FA_Already_Set_Up(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
user.EmailVerified = true;
|
||||
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
{
|
||||
[TwoFactorProviderType.Email] = new TwoFactorProvider
|
||||
{
|
||||
MetaData = new Dictionary<string, object> { ["Email"] = "asdfasf" },
|
||||
Enabled = true
|
||||
}
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
|
||||
|
||||
Assert.False(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void HasPremiumFromOrganization_Returns_False_If_No_Orgs(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyByUserAsync(user.Id).Returns(new List<OrganizationUser>());
|
||||
Assert.False(await sutProvider.Sut.HasPremiumFromOrganization(user));
|
||||
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, false, true)]
|
||||
[InlineCustomAutoData(new[] { typeof(SutProviderCustomization) }, true, false)]
|
||||
public async void HasPremiumFromOrganization_Returns_False_If_Org_Not_Eligible(bool orgEnabled, bool orgUsersGetPremium, SutProvider<UserService> sutProvider, User user, OrganizationUser orgUser, Organization organization)
|
||||
{
|
||||
orgUser.OrganizationId = organization.Id;
|
||||
organization.Enabled = orgEnabled;
|
||||
organization.UsersGetPremium = orgUsersGetPremium;
|
||||
var orgAbilities = new Dictionary<Guid, OrganizationAbility>() { { organization.Id, new OrganizationAbility(organization) } };
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyByUserAsync(user.Id).Returns(new List<OrganizationUser>() { orgUser });
|
||||
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilitiesAsync().Returns(orgAbilities);
|
||||
|
||||
Assert.False(await sutProvider.Sut.HasPremiumFromOrganization(user));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
||||
public async void HasPremiumFromOrganization_Returns_True_If_Org_Eligible(SutProvider<UserService> sutProvider, User user, OrganizationUser orgUser, Organization organization)
|
||||
{
|
||||
orgUser.OrganizationId = organization.Id;
|
||||
organization.Enabled = true;
|
||||
organization.UsersGetPremium = true;
|
||||
var orgAbilities = new Dictionary<Guid, OrganizationAbility>() { { organization.Id, new OrganizationAbility(organization) } };
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyByUserAsync(user.Id).Returns(new List<OrganizationUser>() { orgUser });
|
||||
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilitiesAsync().Returns(orgAbilities);
|
||||
|
||||
Assert.True(await sutProvider.Sut.HasPremiumFromOrganization(user));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user