You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1111 lines
44 KiB
1111 lines
44 KiB
using System.Text.Json; |
|
using Bit.Core.Context; |
|
using Bit.Core.Entities; |
|
using Bit.Core.Exceptions; |
|
using Bit.Core.Platform.Push; |
|
using Bit.Core.Services; |
|
using Bit.Core.Test.AutoFixture.CurrentContextFixtures; |
|
using Bit.Core.Test.Tools.AutoFixture.SendFixtures; |
|
using Bit.Core.Tools.Entities; |
|
using Bit.Core.Tools.Enums; |
|
using Bit.Core.Tools.Models.Business; |
|
using Bit.Core.Tools.Models.Data; |
|
using Bit.Core.Tools.Repositories; |
|
using Bit.Core.Tools.SendFeatures; |
|
using Bit.Core.Tools.SendFeatures.Commands; |
|
using Bit.Core.Tools.Services; |
|
using Bit.Test.Common.AutoFixture.Attributes; |
|
using NSubstitute; |
|
using NSubstitute.ExceptionExtensions; |
|
using Xunit; |
|
|
|
namespace Bit.Core.Test.Tools.Services; |
|
|
|
[SutProviderCustomize] |
|
[CurrentContextCustomize] |
|
[UserSendCustomize] |
|
public class NonAnonymousSendCommandTests |
|
{ |
|
private readonly ISendRepository _sendRepository; |
|
private readonly ISendFileStorageService _sendFileStorageService; |
|
private readonly IPushNotificationService _pushNotificationService; |
|
private readonly ISendAuthorizationService _sendAuthorizationService; |
|
private readonly ISendValidationService _sendValidationService; |
|
private readonly IFeatureService _featureService; |
|
private readonly IReferenceEventService _referenceEventService; |
|
private readonly ICurrentContext _currentContext; |
|
private readonly ISendCoreHelperService _sendCoreHelperService; |
|
private readonly NonAnonymousSendCommand _nonAnonymousSendCommand; |
|
|
|
public NonAnonymousSendCommandTests() |
|
{ |
|
_sendRepository = Substitute.For<ISendRepository>(); |
|
_sendFileStorageService = Substitute.For<ISendFileStorageService>(); |
|
_pushNotificationService = Substitute.For<IPushNotificationService>(); |
|
_sendAuthorizationService = Substitute.For<ISendAuthorizationService>(); |
|
_featureService = Substitute.For<IFeatureService>(); |
|
_sendValidationService = Substitute.For<ISendValidationService>(); |
|
_referenceEventService = Substitute.For<IReferenceEventService>(); |
|
_currentContext = Substitute.For<ICurrentContext>(); |
|
_sendCoreHelperService = Substitute.For<ISendCoreHelperService>(); |
|
|
|
_nonAnonymousSendCommand = new NonAnonymousSendCommand( |
|
_sendRepository, |
|
_sendFileStorageService, |
|
_pushNotificationService, |
|
_sendAuthorizationService, |
|
_sendValidationService, |
|
_referenceEventService, |
|
_currentContext, |
|
_sendCoreHelperService |
|
); |
|
} |
|
|
|
// Disable Send policy check |
|
[Theory] |
|
[InlineData(SendType.File)] |
|
[InlineData(SendType.Text)] |
|
public async Task SaveSendAsync_DisableSend_Applies_throws(SendType sendType) |
|
{ |
|
// Arrange |
|
var send = new Send |
|
{ |
|
Id = default, |
|
Type = sendType, |
|
UserId = Guid.NewGuid() |
|
}; |
|
|
|
var user = new User |
|
{ |
|
Id = send.UserId.Value, |
|
Email = "test@example.com" |
|
}; |
|
|
|
// Configure validation service to throw when DisableSend policy applies |
|
_sendValidationService.ValidateUserCanSaveAsync(send.UserId.Value, send) |
|
.Throws(new BadRequestException("Due to an Enterprise Policy, you are only able to delete an existing Send.")); |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveSendAsync(send)); |
|
|
|
Assert.Contains("Enterprise Policy", exception.Message); |
|
|
|
// Verify the validation service was called |
|
await _sendValidationService.Received(1).ValidateUserCanSaveAsync(send.UserId.Value, send); |
|
|
|
// Verify repository was not called since exception was thrown |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
} |
|
|
|
[Theory] |
|
[InlineData(true)] // New Send (Id is default) |
|
[InlineData(false)] // Existing Send (Id is not default) |
|
public async Task SaveSendAsync_DisableSend_DoesntApply_success(bool isNewSend) |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = isNewSend ? default : Guid.NewGuid(), |
|
Type = SendType.Text, |
|
UserId = userId, |
|
Data = "Text with Notes" |
|
}; |
|
|
|
var initialDate = DateTime.UtcNow.AddMinutes(-5); |
|
send.RevisionDate = initialDate; |
|
|
|
// Configure validation service to NOT throw (policy doesn't apply) |
|
_sendValidationService.ValidateUserCanSaveAsync(userId, send).Returns(Task.CompletedTask); |
|
|
|
// Set up context for reference event |
|
_currentContext.ClientId.Returns("test-client"); |
|
_currentContext.ClientVersion.Returns(Version.Parse("1.0.0")); |
|
|
|
// Act |
|
await _nonAnonymousSendCommand.SaveSendAsync(send); |
|
|
|
// Assert |
|
// Verify validation was checked |
|
await _sendValidationService.Received(1).ValidateUserCanSaveAsync(userId, send); |
|
|
|
if (isNewSend) |
|
{ |
|
// For new Sends |
|
await _sendRepository.Received(1).CreateAsync(send); |
|
await _pushNotificationService.Received(1).PushSyncSendCreateAsync(send); |
|
await _referenceEventService.Received(1).RaiseEventAsync(Arg.Is<ReferenceEvent>(e => |
|
e.Id == userId && |
|
e.Type == ReferenceEventType.SendCreated && |
|
e.Source == ReferenceEventSource.User && |
|
e.SendType == send.Type && |
|
e.SendHasNotes == true && |
|
e.ClientId == "test-client" && |
|
e.ClientVersion == Version.Parse("1.0.0"))); |
|
} |
|
else |
|
{ |
|
// For existing Sends |
|
await _sendRepository.Received(1).UpsertAsync(send); |
|
Assert.NotEqual(initialDate, send.RevisionDate); |
|
await _pushNotificationService.Received(1).PushSyncSendUpdateAsync(send); |
|
await _referenceEventService.DidNotReceive().RaiseEventAsync(Arg.Any<ReferenceEvent>()); |
|
} |
|
} |
|
|
|
[Theory] |
|
[InlineData(true)] // New Send (Id is default) |
|
[InlineData(false)] // Existing Send (Id is not default) |
|
public async Task SaveSendAsync_DisableHideEmail_Applies_throws(bool isNewSend) |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = isNewSend ? default : Guid.NewGuid(), |
|
Type = SendType.Text, |
|
UserId = userId, |
|
HideEmail = true |
|
}; |
|
|
|
// Configure validation service to throw when HideEmail policy applies |
|
_sendValidationService.ValidateUserCanSaveAsync(userId, send) |
|
.Throws(new BadRequestException("Due to an Enterprise Policy, you are not allowed to hide your email address from recipients when creating or editing a Send.")); |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveSendAsync(send)); |
|
|
|
Assert.Contains("hide your email address", exception.Message); |
|
|
|
// Verify validation was called |
|
await _sendValidationService.Received(1).ValidateUserCanSaveAsync(userId, send); |
|
|
|
// Verify repository was not called (exception prevented save) |
|
if (isNewSend) |
|
{ |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
} |
|
else |
|
{ |
|
await _sendRepository.DidNotReceive().UpsertAsync(Arg.Any<Send>()); |
|
} |
|
|
|
// Verify push notification wasn't sent |
|
await _pushNotificationService.DidNotReceive().PushSyncSendCreateAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendUpdateAsync(Arg.Any<Send>()); |
|
} |
|
|
|
[Theory] |
|
[InlineData(true)] // New Send (Id is default) |
|
[InlineData(false)] // Existing Send (Id is not default) |
|
public async Task SaveSendAsync_DisableHideEmail_DoesntApply_success(bool isNewSend) |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = isNewSend ? default : Guid.NewGuid(), |
|
Type = SendType.Text, |
|
UserId = userId, |
|
HideEmail = true // Setting HideEmail to true |
|
}; |
|
|
|
var initialDate = DateTime.UtcNow.AddMinutes(-5); |
|
send.RevisionDate = initialDate; |
|
|
|
// Configure validation service to NOT throw (policy doesn't apply) |
|
_sendValidationService.ValidateUserCanSaveAsync(userId, send).Returns(Task.CompletedTask); |
|
|
|
// Set up context for reference event |
|
_currentContext.ClientId.Returns("test-client"); |
|
_currentContext.ClientVersion.Returns(Version.Parse("1.0.0")); |
|
|
|
// Act |
|
await _nonAnonymousSendCommand.SaveSendAsync(send); |
|
|
|
// Assert |
|
// Verify validation was checked |
|
await _sendValidationService.Received(1).ValidateUserCanSaveAsync(userId, send); |
|
|
|
if (isNewSend) |
|
{ |
|
// For new Sends |
|
await _sendRepository.Received(1).CreateAsync(send); |
|
await _pushNotificationService.Received(1).PushSyncSendCreateAsync(send); |
|
await _referenceEventService.Received(1).RaiseEventAsync(Arg.Is<ReferenceEvent>(e => |
|
e.Id == userId && |
|
e.Type == ReferenceEventType.SendCreated && |
|
e.Source == ReferenceEventSource.User && |
|
e.SendType == send.Type && |
|
e.HasPassword == false && |
|
e.ClientId == "test-client" && |
|
e.ClientVersion == Version.Parse("1.0.0"))); |
|
} |
|
else |
|
{ |
|
// For existing Sends |
|
await _sendRepository.Received(1).UpsertAsync(send); |
|
Assert.NotEqual(initialDate, send.RevisionDate); |
|
await _pushNotificationService.Received(1).PushSyncSendUpdateAsync(send); |
|
await _referenceEventService.DidNotReceive().RaiseEventAsync(Arg.Any<ReferenceEvent>()); |
|
} |
|
} |
|
|
|
[Theory] |
|
[InlineData(SendType.File)] |
|
[InlineData(SendType.Text)] |
|
public async Task SaveSendAsync_DisableSend_Applies_Throws_vNext(SendType sendType) |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = default, |
|
Type = sendType, |
|
UserId = userId |
|
}; |
|
|
|
// Configure validation service to throw when DisableSend policy applies in vNext implementation |
|
_sendValidationService.ValidateUserCanSaveAsync(userId, send) |
|
.Returns(Task.FromException(new BadRequestException("Due to an Enterprise Policy, you are only able to delete an existing Send."))); |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveSendAsync(send)); |
|
|
|
Assert.Contains("Enterprise Policy", exception.Message); |
|
|
|
// Verify validation service was called |
|
await _sendValidationService.Received(1).ValidateUserCanSaveAsync(userId, send); |
|
|
|
// Verify repository and notification methods were not called |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().UpsertAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendCreateAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendUpdateAsync(Arg.Any<Send>()); |
|
await _referenceEventService.DidNotReceive().RaiseEventAsync(Arg.Any<ReferenceEvent>()); |
|
} |
|
|
|
[Theory] |
|
[InlineData(true)] // New Send (Id is default) |
|
[InlineData(false)] // Existing Send (Id is not default) |
|
public async Task SaveSendAsync_DisableSend_DoesntApply_Success_vNext(bool isNewSend) |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = isNewSend ? default : Guid.NewGuid(), |
|
Type = SendType.Text, |
|
UserId = userId, |
|
Data = "Text with Notes" |
|
}; |
|
|
|
var initialDate = DateTime.UtcNow.AddMinutes(-5); |
|
send.RevisionDate = initialDate; |
|
|
|
// Configure validation service to return success for vNext implementation |
|
_sendValidationService.ValidateUserCanSaveAsync(userId, send).Returns(Task.CompletedTask); |
|
|
|
// Set up context for reference event |
|
_currentContext.ClientId.Returns("test-client"); |
|
_currentContext.ClientVersion.Returns(Version.Parse("1.0.0")); |
|
|
|
// Enable feature flag for policy requirements (vNext path) |
|
_featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements).Returns(true); |
|
|
|
// Act |
|
await _nonAnonymousSendCommand.SaveSendAsync(send); |
|
|
|
// Assert |
|
// Verify validation was checked with vNext path |
|
await _sendValidationService.Received(1).ValidateUserCanSaveAsync(userId, send); |
|
|
|
if (isNewSend) |
|
{ |
|
// For new Sends |
|
await _sendRepository.Received(1).CreateAsync(send); |
|
await _pushNotificationService.Received(1).PushSyncSendCreateAsync(send); |
|
await _referenceEventService.Received(1).RaiseEventAsync(Arg.Is<ReferenceEvent>(e => |
|
e.Id == userId && |
|
e.Type == ReferenceEventType.SendCreated && |
|
e.Source == ReferenceEventSource.User && |
|
e.SendType == send.Type && |
|
e.SendHasNotes == true && |
|
e.ClientId == "test-client" && |
|
e.ClientVersion == Version.Parse("1.0.0"))); |
|
} |
|
else |
|
{ |
|
// For existing Sends |
|
await _sendRepository.Received(1).UpsertAsync(send); |
|
Assert.NotEqual(initialDate, send.RevisionDate); |
|
await _pushNotificationService.Received(1).PushSyncSendUpdateAsync(send); |
|
await _referenceEventService.DidNotReceive().RaiseEventAsync(Arg.Any<ReferenceEvent>()); |
|
} |
|
} |
|
|
|
// Send Options Policy - Disable Hide Email check |
|
[Theory] |
|
[InlineData(true)] // New Send (Id is default) |
|
[InlineData(false)] // Existing Send (Id is not default) |
|
public async Task SaveSendAsync_DisableHideEmail_Applies_Throws_vNext(bool isNewSend) |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = isNewSend ? default : Guid.NewGuid(), |
|
Type = SendType.Text, |
|
UserId = userId, |
|
HideEmail = true |
|
}; |
|
|
|
// Enable feature flag for policy requirements (vNext path) |
|
_featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements).Returns(true); |
|
|
|
// Configure validation service to throw when DisableHideEmail policy applies in vNext implementation |
|
_sendValidationService.ValidateUserCanSaveAsync(userId, send) |
|
.Throws(new BadRequestException("Due to an Enterprise Policy, you are not allowed to hide your email address from recipients when creating or editing a Send.")); |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveSendAsync(send)); |
|
|
|
Assert.Contains("hide your email address", exception.Message); |
|
|
|
// Verify validation was called |
|
await _sendValidationService.Received(1).ValidateUserCanSaveAsync(userId, send); |
|
|
|
// Verify repository was not called (exception prevented save) |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().UpsertAsync(Arg.Any<Send>()); |
|
|
|
// Verify push notification wasn't sent |
|
await _pushNotificationService.DidNotReceive().PushSyncSendCreateAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendUpdateAsync(Arg.Any<Send>()); |
|
|
|
// Verify reference event service wasn't called |
|
await _referenceEventService.DidNotReceive().RaiseEventAsync(Arg.Any<ReferenceEvent>()); |
|
} |
|
|
|
[Theory] |
|
[InlineData(true)] // New Send (Id is default) |
|
[InlineData(false)] // Existing Send (Id is not default) |
|
public async Task SaveSendAsync_DisableHideEmail_Applies_ButEmailNotHidden_Success_vNext(bool isNewSend) |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = isNewSend ? default : Guid.NewGuid(), |
|
Type = SendType.Text, |
|
UserId = userId, |
|
HideEmail = false // Email is not hidden, so policy doesn't block |
|
}; |
|
|
|
var initialDate = DateTime.UtcNow.AddMinutes(-5); |
|
send.RevisionDate = initialDate; |
|
|
|
// Enable feature flag for policy requirements (vNext path) |
|
_featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements).Returns(true); |
|
|
|
// Configure validation service to allow saves when HideEmail is false |
|
_sendValidationService.ValidateUserCanSaveAsync(userId, send).Returns(Task.CompletedTask); |
|
|
|
// Set up context for reference event |
|
_currentContext.ClientId.Returns("test-client"); |
|
_currentContext.ClientVersion.Returns(Version.Parse("1.0.0")); |
|
|
|
// Act |
|
await _nonAnonymousSendCommand.SaveSendAsync(send); |
|
|
|
// Assert |
|
// Verify validation was called with vNext path |
|
await _sendValidationService.Received(1).ValidateUserCanSaveAsync(userId, send); |
|
|
|
if (isNewSend) |
|
{ |
|
// For new Sends |
|
await _sendRepository.Received(1).CreateAsync(send); |
|
await _pushNotificationService.Received(1).PushSyncSendCreateAsync(send); |
|
await _referenceEventService.Received(1).RaiseEventAsync(Arg.Is<ReferenceEvent>(e => |
|
e.Id == userId && |
|
e.Type == ReferenceEventType.SendCreated && |
|
e.Source == ReferenceEventSource.User && |
|
e.SendType == send.Type && |
|
e.ClientId == "test-client" && |
|
e.ClientVersion == Version.Parse("1.0.0"))); |
|
} |
|
else |
|
{ |
|
// For existing Sends |
|
await _sendRepository.Received(1).UpsertAsync(send); |
|
Assert.NotEqual(initialDate, send.RevisionDate); |
|
await _pushNotificationService.Received(1).PushSyncSendUpdateAsync(send); |
|
await _referenceEventService.DidNotReceive().RaiseEventAsync(Arg.Any<ReferenceEvent>()); |
|
} |
|
} |
|
|
|
[Fact] |
|
public async Task SaveSendAsync_ExistingSend_Updates() |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var sendId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = sendId, |
|
Type = SendType.Text, |
|
UserId = userId, |
|
Data = "Some text data" |
|
}; |
|
|
|
var initialDate = DateTime.UtcNow.AddMinutes(-5); |
|
send.RevisionDate = initialDate; |
|
|
|
// Act |
|
await _nonAnonymousSendCommand.SaveSendAsync(send); |
|
|
|
// Assert |
|
// Verify validation was called |
|
await _sendValidationService.Received(1).ValidateUserCanSaveAsync(userId, send); |
|
|
|
// Verify repository was called with updated send |
|
await _sendRepository.Received(1).UpsertAsync(send); |
|
|
|
// Check that the revision date was updated |
|
Assert.NotEqual(initialDate, send.RevisionDate); |
|
|
|
// Verify push notification was sent for the update |
|
await _pushNotificationService.Received(1).PushSyncSendUpdateAsync(send); |
|
|
|
// Verify no reference event was raised (only happens for new sends) |
|
await _referenceEventService.DidNotReceive().RaiseEventAsync(Arg.Any<ReferenceEvent>()); |
|
} |
|
|
|
[Fact] |
|
public async Task SaveFileSendAsync_TextType_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.Text, // Text type instead of File |
|
UserId = userId |
|
}; |
|
var fileData = new SendFileData(); |
|
var fileLength = 1024L; // 1KB |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveFileSendAsync(send, fileData, fileLength)); |
|
|
|
Assert.Contains("not of type \"file\"", exception.Message); |
|
|
|
// Verify no further methods were called |
|
await _sendValidationService.DidNotReceive().StorageRemainingForSendAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().UpsertAsync(Arg.Any<Send>()); |
|
await _sendFileStorageService.DidNotReceive().GetSendFileUploadUrlAsync(Arg.Any<Send>(), Arg.Any<string>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendCreateAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendUpdateAsync(Arg.Any<Send>()); |
|
} |
|
|
|
[Fact] |
|
public async Task SaveFileSendAsync_EmptyFile_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.File, |
|
UserId = userId |
|
}; |
|
var fileData = new SendFileData(); |
|
var fileLength = 0L; // Empty file |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveFileSendAsync(send, fileData, fileLength)); |
|
|
|
Assert.Contains("No file data", exception.Message); |
|
|
|
// Verify no methods were called after validation failed |
|
await _sendValidationService.DidNotReceive().StorageRemainingForSendAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().UpsertAsync(Arg.Any<Send>()); |
|
await _sendFileStorageService.DidNotReceive().GetSendFileUploadUrlAsync(Arg.Any<Send>(), Arg.Any<string>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendCreateAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendUpdateAsync(Arg.Any<Send>()); |
|
} |
|
|
|
[Fact] |
|
public async Task SaveFileSendAsync_UserCannotAccessPremium_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.File, |
|
UserId = userId |
|
}; |
|
var fileData = new SendFileData(); |
|
var fileLength = 1024L; // 1KB |
|
|
|
// Configure validation service to throw when checking storage |
|
_sendValidationService.StorageRemainingForSendAsync(send) |
|
.Throws(new BadRequestException("You must have premium status to use file Sends.")); |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveFileSendAsync(send, fileData, fileLength)); |
|
|
|
Assert.Contains("premium status", exception.Message); |
|
|
|
// Verify storage validation was called |
|
await _sendValidationService.Received(1).StorageRemainingForSendAsync(send); |
|
|
|
// Verify no further methods were called |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().UpsertAsync(Arg.Any<Send>()); |
|
await _sendFileStorageService.DidNotReceive().GetSendFileUploadUrlAsync(Arg.Any<Send>(), Arg.Any<string>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendCreateAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendUpdateAsync(Arg.Any<Send>()); |
|
} |
|
|
|
[Fact] |
|
public async Task SaveFileSendAsync_UserHasUnconfirmedEmail_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.File, |
|
UserId = userId |
|
}; |
|
var fileData = new SendFileData(); |
|
var fileLength = 1024L; // 1KB |
|
|
|
// Configure validation service to pass storage check |
|
_sendValidationService.StorageRemainingForSendAsync(send).Returns(10240L); // 10KB remaining |
|
|
|
// Configure validation service to throw when checking user can save |
|
_sendValidationService.When(x => x.ValidateUserCanSaveAsync(userId, send)) |
|
.Throw(new BadRequestException("You must confirm your email before creating a Send.")); |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveFileSendAsync(send, fileData, fileLength)); |
|
|
|
Assert.Contains("confirm your email", exception.Message); |
|
|
|
// Verify storage validation was called |
|
await _sendValidationService.Received(1).StorageRemainingForSendAsync(send); |
|
|
|
// Verify SaveSendAsync attempted to be called, triggering email validation |
|
await _sendValidationService.Received(1).ValidateUserCanSaveAsync(userId, send); |
|
|
|
// Verify no repository or notification methods were called after validation failed |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().UpsertAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendCreateAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendUpdateAsync(Arg.Any<Send>()); |
|
} |
|
|
|
[Fact] |
|
public async Task SaveFileSendAsync_UserCanAccessPremium_HasNoStorage_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.File, |
|
UserId = userId |
|
}; |
|
var fileData = new SendFileData(); |
|
var fileLength = 1024L; // 1KB |
|
|
|
// Configure validation service to return 0 storage remaining |
|
_sendValidationService.StorageRemainingForSendAsync(send).Returns(0L); |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveFileSendAsync(send, fileData, fileLength)); |
|
|
|
Assert.Contains("Not enough storage available", exception.Message); |
|
|
|
// Verify storage validation was called |
|
await _sendValidationService.Received(1).StorageRemainingForSendAsync(send); |
|
|
|
// Verify no further methods were called |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().UpsertAsync(Arg.Any<Send>()); |
|
await _sendFileStorageService.DidNotReceive().GetSendFileUploadUrlAsync(Arg.Any<Send>(), Arg.Any<string>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendCreateAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendUpdateAsync(Arg.Any<Send>()); |
|
} |
|
|
|
[Fact] |
|
public async Task SaveFileSendAsync_UserCanAccessPremium_StorageFull_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.File, |
|
UserId = userId |
|
}; |
|
var fileData = new SendFileData(); |
|
var fileLength = 1024L; // 1KB |
|
|
|
// Configure validation service to return less storage remaining than needed |
|
_sendValidationService.StorageRemainingForSendAsync(send).Returns(512L); // Only 512 bytes available |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveFileSendAsync(send, fileData, fileLength)); |
|
|
|
Assert.Contains("Not enough storage available", exception.Message); |
|
|
|
// Verify storage validation was called |
|
await _sendValidationService.Received(1).StorageRemainingForSendAsync(send); |
|
|
|
// Verify no further methods were called |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().UpsertAsync(Arg.Any<Send>()); |
|
await _sendFileStorageService.DidNotReceive().GetSendFileUploadUrlAsync(Arg.Any<Send>(), Arg.Any<string>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendCreateAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendUpdateAsync(Arg.Any<Send>()); |
|
} |
|
|
|
[Fact] |
|
public async Task SaveFileSendAsync_UserCanAccessPremium_IsNotPremium_IsSelfHosted_GiantFile_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.File, |
|
UserId = userId |
|
}; |
|
var fileData = new SendFileData(); |
|
var fileLength = 15L * 1024L * 1024L * 1024L; // 15GB |
|
|
|
// Configure validation service to return large but insufficient storage (10GB for self-hosted non-premium) |
|
_sendValidationService.StorageRemainingForSendAsync(send) |
|
.Returns(10L * 1024L * 1024L * 1024L); // 10GB remaining (self-hosted default) |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveFileSendAsync(send, fileData, fileLength)); |
|
|
|
Assert.Contains("Not enough storage available", exception.Message); |
|
|
|
// Verify storage validation was called |
|
await _sendValidationService.Received(1).StorageRemainingForSendAsync(send); |
|
|
|
// Verify no further methods were called |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().UpsertAsync(Arg.Any<Send>()); |
|
await _sendFileStorageService.DidNotReceive().GetSendFileUploadUrlAsync(Arg.Any<Send>(), Arg.Any<string>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendCreateAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendUpdateAsync(Arg.Any<Send>()); |
|
} |
|
|
|
[Fact] |
|
public async Task SaveFileSendAsync_UserCanAccessPremium_IsNotPremium_IsNotSelfHosted_TwoGigabyteFile_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.File, |
|
UserId = userId |
|
}; |
|
var fileData = new SendFileData(); |
|
var fileLength = 2L * 1024L * 1024L * 1024L; // 2GB |
|
|
|
// Configure validation service to return 1GB storage (cloud non-premium default) |
|
_sendValidationService.StorageRemainingForSendAsync(send) |
|
.Returns(1L * 1024L * 1024L * 1024L); // 1GB remaining (cloud default) |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveFileSendAsync(send, fileData, fileLength)); |
|
|
|
Assert.Contains("Not enough storage available", exception.Message); |
|
|
|
// Verify storage validation was called |
|
await _sendValidationService.Received(1).StorageRemainingForSendAsync(send); |
|
|
|
// Verify no further methods were called |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().UpsertAsync(Arg.Any<Send>()); |
|
await _sendFileStorageService.DidNotReceive().GetSendFileUploadUrlAsync(Arg.Any<Send>(), Arg.Any<string>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendCreateAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendUpdateAsync(Arg.Any<Send>()); |
|
} |
|
|
|
[Fact] |
|
public async Task SaveFileSendAsync_ThroughOrg_MaxStorageIsNull_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
var organizationId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.File, |
|
OrganizationId = organizationId |
|
}; |
|
|
|
var fileData = new SendFileData |
|
{ |
|
FileName = "test.txt" |
|
}; |
|
|
|
const long fileLength = 1000; |
|
|
|
// Set up validation service to return 0 storage remaining |
|
// This simulates the case when an organization's max storage is null |
|
_sendValidationService.StorageRemainingForSendAsync(send).Returns(0L); |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveFileSendAsync(send, fileData, fileLength)); |
|
|
|
Assert.Equal("Not enough storage available.", exception.Message); |
|
|
|
// Verify the method was called exactly once |
|
await _sendValidationService.Received(1).StorageRemainingForSendAsync(send); |
|
} |
|
|
|
[Fact] |
|
public async Task SaveFileSendAsync_ThroughOrg_MaxStorageIsNull_TwoGBFile_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
var orgId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.File, |
|
OrganizationId = orgId, |
|
UserId = null |
|
}; |
|
var fileData = new SendFileData(); |
|
var fileLength = 2L * 1024L * 1024L * 1024L; // 2GB |
|
|
|
// Configure validation service to throw BadRequest when checking storage for org without storage |
|
_sendValidationService.StorageRemainingForSendAsync(send) |
|
.Throws(new BadRequestException("This organization cannot use file sends.")); |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveFileSendAsync(send, fileData, fileLength)); |
|
|
|
Assert.Contains("This organization cannot use file sends", exception.Message); |
|
|
|
// Verify storage validation was called |
|
await _sendValidationService.Received(1).StorageRemainingForSendAsync(send); |
|
|
|
// Verify no further methods were called |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().UpsertAsync(Arg.Any<Send>()); |
|
await _sendFileStorageService.DidNotReceive().GetSendFileUploadUrlAsync(Arg.Any<Send>(), Arg.Any<string>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendCreateAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendUpdateAsync(Arg.Any<Send>()); |
|
} |
|
|
|
[Fact] |
|
public async Task SaveFileSendAsync_ThroughOrg_MaxStorageIsOneGB_TwoGBFile_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
var orgId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.File, |
|
OrganizationId = orgId, |
|
UserId = null |
|
}; |
|
var fileData = new SendFileData(); |
|
var fileLength = 2L * 1024L * 1024L * 1024L; // 2GB |
|
|
|
// Configure validation service to return 1GB storage (org's max storage limit) |
|
_sendValidationService.StorageRemainingForSendAsync(send) |
|
.Returns(1L * 1024L * 1024L * 1024L); // 1GB remaining |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.SaveFileSendAsync(send, fileData, fileLength)); |
|
|
|
Assert.Contains("Not enough storage available", exception.Message); |
|
|
|
// Verify storage validation was called |
|
await _sendValidationService.Received(1).StorageRemainingForSendAsync(send); |
|
|
|
// Verify no further methods were called |
|
await _sendRepository.DidNotReceive().CreateAsync(Arg.Any<Send>()); |
|
await _sendRepository.DidNotReceive().UpsertAsync(Arg.Any<Send>()); |
|
await _sendFileStorageService.DidNotReceive().GetSendFileUploadUrlAsync(Arg.Any<Send>(), Arg.Any<string>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendCreateAsync(Arg.Any<Send>()); |
|
await _pushNotificationService.DidNotReceive().PushSyncSendUpdateAsync(Arg.Any<Send>()); |
|
} |
|
|
|
[Fact] |
|
public async Task SaveFileSendAsync_HasEnoughStorage_Success() |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.File, |
|
UserId = userId |
|
}; |
|
var fileData = new SendFileData(); |
|
var fileLength = 500L * 1024L; // 500KB |
|
var expectedFileId = "generatedfileid"; |
|
var expectedUploadUrl = "https://upload.example.com/url"; |
|
|
|
// Configure storage validation to return more storage than needed |
|
_sendValidationService.StorageRemainingForSendAsync(send) |
|
.Returns(1024L * 1024L); // 1MB remaining |
|
|
|
// Configure file storage service to return upload URL |
|
_sendFileStorageService.GetSendFileUploadUrlAsync(Arg.Any<Send>(), Arg.Any<string>()) |
|
.Returns(expectedUploadUrl); |
|
|
|
// Set up string generator to return predictable file ID |
|
_sendCoreHelperService.SecureRandomString(32, false, false) |
|
.Returns(expectedFileId); |
|
|
|
// Act |
|
var result = await _nonAnonymousSendCommand.SaveFileSendAsync(send, fileData, fileLength); |
|
|
|
// Assert |
|
Assert.Equal(expectedUploadUrl, result); |
|
|
|
// Verify storage validation was called |
|
await _sendValidationService.Received(1).StorageRemainingForSendAsync(send); |
|
|
|
// Verify upload URL was requested |
|
await _sendFileStorageService.Received(1).GetSendFileUploadUrlAsync(send, expectedFileId); |
|
} |
|
|
|
[Fact] |
|
public async Task SaveFileSendAsync_HasEnoughStorage_SendFileThrows_CleansUp() |
|
{ |
|
// Arrange |
|
var userId = Guid.NewGuid(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.File, |
|
UserId = userId |
|
}; |
|
var fileData = new SendFileData(); |
|
var fileLength = 500L * 1024L; // 500KB |
|
var expectedFileId = "generatedfileid"; |
|
|
|
// Configure storage validation to return more storage than needed |
|
_sendValidationService.StorageRemainingForSendAsync(send) |
|
.Returns(1024L * 1024L); // 1MB remaining |
|
|
|
// Set up string generator to return predictable file ID |
|
_sendCoreHelperService.SecureRandomString(32, false, false) |
|
.Returns(expectedFileId); |
|
|
|
// Configure file storage service to throw exception when getting upload URL |
|
_sendFileStorageService.GetSendFileUploadUrlAsync(Arg.Any<Send>(), Arg.Any<string>()) |
|
.Throws(new Exception("Storage service unavailable")); |
|
|
|
// Act & Assert |
|
await Assert.ThrowsAsync<Exception>(() => |
|
_nonAnonymousSendCommand.SaveFileSendAsync(send, fileData, fileLength)); |
|
|
|
// Verify storage validation was called |
|
await _sendValidationService.Received(1).StorageRemainingForSendAsync(send); |
|
|
|
// Verify file was cleaned up after failure |
|
await _sendFileStorageService.Received(1).DeleteFileAsync(send, expectedFileId); |
|
} |
|
|
|
[Fact] |
|
public async Task UpdateFileToExistingSendAsync_SendNull_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
Stream stream = new MemoryStream(); |
|
Send send = null; |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.UploadFileToExistingSendAsync(stream, send)); |
|
|
|
Assert.Equal("Send does not have file data", exception.Message); |
|
|
|
// Verify no interactions with storage service |
|
await _sendFileStorageService.DidNotReceiveWithAnyArgs().UploadNewFileAsync( |
|
Arg.Any<Stream>(), Arg.Any<Send>(), Arg.Any<string>()); |
|
} |
|
|
|
[Fact] |
|
public async Task UpdateFileToExistingSendAsync_SendDataNull_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
Stream stream = new MemoryStream(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.File, |
|
UserId = Guid.NewGuid(), |
|
Data = null // Send exists but has null Data property |
|
}; |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.UploadFileToExistingSendAsync(stream, send)); |
|
|
|
Assert.Equal("Send does not have file data", exception.Message); |
|
|
|
// Verify no interactions with storage service |
|
await _sendFileStorageService.DidNotReceiveWithAnyArgs().UploadNewFileAsync( |
|
Arg.Any<Stream>(), Arg.Any<Send>(), Arg.Any<string>()); |
|
} |
|
|
|
[Fact] |
|
public async Task UpdateFileToExistingSendAsync_NotFileType_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
Stream stream = new MemoryStream(); |
|
var send = new Send |
|
{ |
|
Id = Guid.NewGuid(), |
|
Type = SendType.Text, // Not a file type |
|
UserId = Guid.NewGuid(), |
|
Data = "{\"someData\":\"value\"}" // Has data, but not file data |
|
}; |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.UploadFileToExistingSendAsync(stream, send)); |
|
|
|
Assert.Equal("Not a File Type Send.", exception.Message); |
|
|
|
// Verify no interactions with storage service |
|
await _sendFileStorageService.DidNotReceiveWithAnyArgs().UploadNewFileAsync( |
|
Arg.Any<Stream>(), Arg.Any<Send>(), Arg.Any<string>()); |
|
} |
|
|
|
[Fact] |
|
public async Task UpdateFileToExistingSendAsync_StreamPositionRestToZero_Success() |
|
{ |
|
// Arrange |
|
var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); |
|
stream.Position = 2; |
|
var sendId = Guid.NewGuid(); |
|
var userId = Guid.NewGuid(); |
|
var fileId = "existingfileid123"; |
|
|
|
var sendFileData = new SendFileData { Id = fileId, Size = 1000, Validated = false }; |
|
var send = new Send |
|
{ |
|
Id = sendId, |
|
UserId = userId, |
|
Type = SendType.File, |
|
Data = JsonSerializer.Serialize(sendFileData) |
|
}; |
|
|
|
// Setup validation to succeed |
|
_sendFileStorageService.ValidateFileAsync(send, sendFileData.Id, sendFileData.Size, SendFileSettingHelper.FILE_SIZE_LEEWAY).Returns((true, sendFileData.Size)); |
|
|
|
// Act |
|
await _nonAnonymousSendCommand.UploadFileToExistingSendAsync(stream, send); |
|
|
|
// Assert |
|
// Verify file was uploaded with correct parameters |
|
await _sendFileStorageService.Received(1).UploadNewFileAsync( |
|
Arg.Is<Stream>(s => s == stream && s.Position == 0), // Ensure stream position is reset |
|
Arg.Is<Send>(s => s.Id == sendId && s.UserId == userId), |
|
Arg.Is<string>(id => id == fileId) |
|
); |
|
} |
|
|
|
|
|
[Fact] |
|
public async Task UploadFileToExistingSendAsync_Success() |
|
{ |
|
// Arrange |
|
var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); |
|
stream.Position = 2; // Simulate a non-zero position |
|
var sendId = Guid.NewGuid(); |
|
var userId = Guid.NewGuid(); |
|
var fileId = "existingfileid123"; |
|
|
|
var sendFileData = new SendFileData { Id = fileId, Size = 1000, Validated = false }; |
|
var send = new Send |
|
{ |
|
Id = sendId, |
|
UserId = userId, |
|
Type = SendType.File, |
|
Data = JsonSerializer.Serialize(sendFileData) |
|
}; |
|
|
|
_sendFileStorageService.ValidateFileAsync(send, sendFileData.Id, sendFileData.Size, SendFileSettingHelper.FILE_SIZE_LEEWAY).Returns((true, sendFileData.Size)); |
|
|
|
// Act |
|
await _nonAnonymousSendCommand.UploadFileToExistingSendAsync(stream, send); |
|
|
|
// Assert |
|
// Verify file was uploaded with correct parameters |
|
await _sendFileStorageService.Received(1).UploadNewFileAsync( |
|
Arg.Is<Stream>(s => s == stream && s.Position == 0), // Ensure stream position is reset |
|
Arg.Is<Send>(s => s.Id == sendId && s.UserId == userId), |
|
Arg.Is<string>(id => id == fileId) |
|
); |
|
} |
|
|
|
[Fact] |
|
public async Task UpdateFileToExistingSendAsync_InvalidSize_ThrowsBadRequest() |
|
{ |
|
// Arrange |
|
var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); |
|
var sendId = Guid.NewGuid(); |
|
var userId = Guid.NewGuid(); |
|
var fileId = "existingfileid123"; |
|
|
|
var sendFileData = new SendFileData { Id = fileId, Size = 1000, Validated = false }; |
|
var send = new Send |
|
{ |
|
Id = sendId, |
|
UserId = userId, |
|
Type = SendType.File, |
|
Data = JsonSerializer.Serialize(sendFileData) |
|
}; |
|
|
|
// Configure storage service to upload successfully |
|
_sendFileStorageService.UploadNewFileAsync( |
|
Arg.Any<Stream>(), Arg.Any<Send>(), Arg.Any<string>()) |
|
.Returns(Task.CompletedTask); |
|
|
|
// Configure validation to fail due to file size mismatch |
|
_nonAnonymousSendCommand.ConfirmFileSize(send) |
|
.Returns(false); |
|
|
|
// Act & Assert |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
_nonAnonymousSendCommand.UploadFileToExistingSendAsync(stream, send)); |
|
|
|
Assert.Equal("File received does not match expected file length.", exception.Message); |
|
} |
|
}
|
|
|