diff --git a/test/Core.Test/Auth/UserFeatures/EmergencyAccess/DeleteEmergencyAccessCommandTests.cs b/test/Core.Test/Auth/UserFeatures/EmergencyAccess/DeleteEmergencyAccessCommandTests.cs
index 0b47b97472..88d6a2b404 100644
--- a/test/Core.Test/Auth/UserFeatures/EmergencyAccess/DeleteEmergencyAccessCommandTests.cs
+++ b/test/Core.Test/Auth/UserFeatures/EmergencyAccess/DeleteEmergencyAccessCommandTests.cs
@@ -1,5 +1,4 @@
-using Bit.Core.Auth.Enums;
-using Bit.Core.Auth.Models.Data;
+using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.UserFeatures.EmergencyAccess.Commands;
using Bit.Core.Auth.UserFeatures.EmergencyAccess.Mail;
using Bit.Core.Exceptions;
@@ -15,6 +14,10 @@ namespace Bit.Core.Test.Auth.UserFeatures.EmergencyAccess;
[SutProviderCustomize]
public class DeleteEmergencyAccessCommandTests
{
+ ///
+ /// Verifies that attempting to delete a non-existent emergency access record
+ /// throws a and does not call delete or send email.
+ ///
[Theory, BitAutoData]
public async Task DeleteByIdGrantorIdAsync_EmergencyAccessNotFound_ThrowsBadRequest(
SutProvider sutProvider,
@@ -37,41 +40,36 @@ public class DeleteEmergencyAccessCommandTests
.SendEmail(default);
}
+ ///
+ /// Verifies that a valid delete request successfully deletes the emergency access record,
+ /// returns the deleted details, and sends a notification email to the grantor.
+ ///
[Theory, BitAutoData]
public async Task DeleteByIdGrantorIdAsync_ValidRequest_DeletesAndReturnsDetails(
SutProvider sutProvider,
- Guid emergencyAccessId,
- Guid grantorId,
- Guid granteeId)
+ EmergencyAccessDetails emergencyAccessDetails)
{
- var emergencyAccessDetails = new EmergencyAccessDetails
- {
- Id = emergencyAccessId,
- GrantorId = grantorId,
- GranteeId = granteeId,
- GranteeEmail = "grantee@test.dev",
- GrantorEmail = "grantor@test.dev",
- Status = EmergencyAccessStatusType.Confirmed,
- Type = EmergencyAccessType.View
- };
-
sutProvider.GetDependency()
- .GetDetailsByIdGrantorIdAsync(emergencyAccessId, grantorId)
+ .GetDetailsByIdGrantorIdAsync(emergencyAccessDetails.Id, emergencyAccessDetails.GrantorId)
.Returns(emergencyAccessDetails);
- var result = await sutProvider.Sut.DeleteByIdGrantorIdAsync(emergencyAccessId, grantorId);
+ var result = await sutProvider.Sut.DeleteByIdGrantorIdAsync(emergencyAccessDetails.Id, emergencyAccessDetails.GrantorId);
Assert.NotNull(result);
- Assert.Equal(emergencyAccessId, result.Id);
- Assert.Equal(grantorId, result.GrantorId);
+ Assert.Equal(emergencyAccessDetails.Id, result.Id);
+ Assert.Equal(emergencyAccessDetails.GrantorId, result.GrantorId);
await sutProvider.GetDependency()
.Received(1)
- .DeleteAsync(Arg.Is(ea => ea.Id == emergencyAccessId));
+ .DeleteAsync(Arg.Is(ea => ea.Id == emergencyAccessDetails.Id));
await sutProvider.GetDependency()
.Received(1)
.SendEmail(Arg.Any());
}
+ ///
+ /// Verifies that when a grantor has no emergency access records, the method returns
+ /// an empty collection and does not attempt to delete or send email.
+ ///
[Theory, BitAutoData]
public async Task DeleteAllByGrantorIdAsync_NoEmergencyAccessRecords_ReturnsEmptyCollection(
SutProvider sutProvider,
@@ -79,7 +77,7 @@ public class DeleteEmergencyAccessCommandTests
{
sutProvider.GetDependency()
.GetManyDetailsByGrantorIdAsync(grantorId)
- .Returns(new List());
+ .Returns([]);
var result = await sutProvider.Sut.DeleteAllByGrantorIdAsync(grantorId);
@@ -93,42 +91,22 @@ public class DeleteEmergencyAccessCommandTests
.SendEmail(default);
}
+ ///
+ /// Verifies that when a grantor has multiple emergency access records, all records are deleted,
+ /// the details are returned, and a single notification email is sent.
+ ///
[Theory, BitAutoData]
public async Task DeleteAllByGrantorIdAsync_MultipleRecords_DeletesAllAndReturnsDetails(
SutProvider sutProvider,
+ EmergencyAccessDetails emergencyAccessDetails1,
+ EmergencyAccessDetails emergencyAccessDetails2,
+ EmergencyAccessDetails emergencyAccessDetails3,
Guid grantorId)
{
- var emergencyAccessDetails1 = new EmergencyAccessDetails
- {
- Id = Guid.NewGuid(),
- GrantorId = grantorId,
- GranteeId = Guid.NewGuid(),
- GranteeEmail = "grantee@test.dev",
- GrantorEmail = "grantor@test.dev",
- Status = EmergencyAccessStatusType.Confirmed,
- Type = EmergencyAccessType.View
- };
-
- var emergencyAccessDetails2 = new EmergencyAccessDetails
- {
- Id = Guid.NewGuid(),
- GrantorId = grantorId,
- GranteeId = Guid.NewGuid(),
- GranteeEmail = "grantee@test.dev",
- GrantorEmail = "grantor@test.dev",
- Status = EmergencyAccessStatusType.Invited,
- Type = EmergencyAccessType.Takeover
- };
-
- var emergencyAccessDetails3 = new EmergencyAccessDetails
- {
- Id = Guid.NewGuid(),
- GrantorId = grantorId,
- GranteeId = Guid.NewGuid(),
- GranteeEmail = "grantee@test.dev",
- GrantorEmail = "grantor@test.dev",
- Type = EmergencyAccessType.View
- };
+ // link all details to the same grantor
+ emergencyAccessDetails1.GrantorId = grantorId;
+ emergencyAccessDetails2.GrantorId = grantorId;
+ emergencyAccessDetails3.GrantorId = grantorId;
var allDetails = new List
{
@@ -153,24 +131,16 @@ public class DeleteEmergencyAccessCommandTests
.SendEmail(Arg.Any());
}
+ ///
+ /// Verifies that when a grantor has a single emergency access record, it is deleted,
+ /// the details are returned, and a notification email is sent.
+ ///
[Theory, BitAutoData]
public async Task DeleteAllByGrantorIdAsync_SingleRecord_DeletesAndReturnsDetails(
SutProvider sutProvider,
- Guid grantorId,
- Guid granteeId)
+ EmergencyAccessDetails emergencyAccessDetails,
+ Guid grantorId)
{
- var emergencyAccessId = Guid.NewGuid();
- var emergencyAccessDetails = new EmergencyAccessDetails
- {
- Id = emergencyAccessId,
- GrantorId = grantorId,
- GranteeId = granteeId,
- GranteeEmail = "grantee@test.dev",
- GrantorEmail = "grantor@test.dev",
- Status = EmergencyAccessStatusType.Confirmed,
- Type = EmergencyAccessType.Takeover
- };
-
sutProvider.GetDependency()
.GetManyDetailsByGrantorIdAsync(grantorId)
.Returns([emergencyAccessDetails]);
@@ -179,10 +149,103 @@ public class DeleteEmergencyAccessCommandTests
Assert.NotNull(result);
Assert.Single(result);
- Assert.Equal(emergencyAccessId, result.First().Id);
+ Assert.Equal(emergencyAccessDetails.Id, result.First().Id);
await sutProvider.GetDependency()
.Received(1)
- .DeleteAsync(Arg.Is(ea => ea.Id == emergencyAccessId));
+ .DeleteAsync(Arg.Is(ea => ea.Id == emergencyAccessDetails.Id));
+ await sutProvider.GetDependency()
+ .Received(1)
+ .SendEmail(Arg.Any());
+ }
+
+ ///
+ /// Verifies that when a grantee has no emergency access records, the method returns
+ /// an empty collection and does not attempt to delete or send email.
+ ///
+ [Theory, BitAutoData]
+ public async Task DeleteAllByGranteeIdAsync_NoEmergencyAccessRecords_ReturnsEmptyCollection(
+ SutProvider sutProvider,
+ Guid granteeId)
+ {
+ sutProvider.GetDependency()
+ .GetManyDetailsByGranteeIdAsync(granteeId)
+ .Returns([]);
+
+ var result = await sutProvider.Sut.DeleteAllByGranteeIdAsync(granteeId);
+
+ Assert.NotNull(result);
+ Assert.Empty(result);
+ await sutProvider.GetDependency()
+ .DidNotReceiveWithAnyArgs()
+ .DeleteAsync(default);
+ await sutProvider.GetDependency()
+ .DidNotReceiveWithAnyArgs()
+ .SendEmail(default);
+ }
+
+ ///
+ /// Verifies that when a grantee has a single emergency access record, it is deleted,
+ /// the details are returned, and a notification email is sent to the grantor.
+ ///
+ [Theory, BitAutoData]
+ public async Task DeleteAllByGranteeIdAsync_SingleRecord_DeletesAndReturnsDetails(
+ SutProvider sutProvider,
+ EmergencyAccessDetails emergencyAccessDetails,
+ Guid granteeId)
+ {
+ sutProvider.GetDependency()
+ .GetManyDetailsByGranteeIdAsync(granteeId)
+ .Returns([emergencyAccessDetails]);
+
+ var result = await sutProvider.Sut.DeleteAllByGranteeIdAsync(granteeId);
+
+ Assert.NotNull(result);
+ Assert.Single(result);
+ Assert.Equal(emergencyAccessDetails.Id, result.First().Id);
+ await sutProvider.GetDependency()
+ .Received(1)
+ .DeleteAsync(Arg.Is(ea => ea.Id == emergencyAccessDetails.Id));
+ await sutProvider.GetDependency()
+ .Received(1)
+ .SendEmail(Arg.Any());
+ }
+
+ ///
+ /// Verifies that when a grantee has multiple emergency access records from different grantors,
+ /// all records are deleted, the details are returned, and a single notification email is sent
+ /// to all affected grantors.
+ ///
+ [Theory, BitAutoData]
+ public async Task DeleteAllByGranteeIdAsync_MultipleRecords_DeletesAllAndReturnsDetails(
+ SutProvider sutProvider,
+ EmergencyAccessDetails emergencyAccessDetails1,
+ EmergencyAccessDetails emergencyAccessDetails2,
+ EmergencyAccessDetails emergencyAccessDetails3,
+ Guid granteeId)
+ {
+ // link all details to the same grantee
+ emergencyAccessDetails1.GranteeId = granteeId;
+ emergencyAccessDetails2.GranteeId = granteeId;
+ emergencyAccessDetails3.GranteeId = granteeId;
+
+ var allDetails = new List
+ {
+ emergencyAccessDetails1,
+ emergencyAccessDetails2,
+ emergencyAccessDetails3
+ };
+
+ sutProvider.GetDependency()
+ .GetManyDetailsByGranteeIdAsync(granteeId)
+ .Returns(allDetails);
+
+ var result = await sutProvider.Sut.DeleteAllByGranteeIdAsync(granteeId);
+
+ Assert.NotNull(result);
+ Assert.Equal(3, result.Count);
+ await sutProvider.GetDependency()
+ .Received(3)
+ .DeleteAsync(Arg.Any());
await sutProvider.GetDependency()
.Received(1)
.SendEmail(Arg.Any());
diff --git a/test/Core.Test/Auth/UserFeatures/EmergencyAccess/EmergencyAccessMailTests.cs b/test/Core.Test/Auth/UserFeatures/EmergencyAccess/EmergencyAccessMailTests.cs
index 0a64c59d58..cee2f64fc4 100644
--- a/test/Core.Test/Auth/UserFeatures/EmergencyAccess/EmergencyAccessMailTests.cs
+++ b/test/Core.Test/Auth/UserFeatures/EmergencyAccess/EmergencyAccessMailTests.cs
@@ -26,7 +26,7 @@ public class EmergencyAccessMailTests
[Theory, BitAutoData]
public async Task SendEmergencyAccessRemoveGranteesEmail_SingleGrantee_Success(
string grantorEmail,
- string granteeName)
+ string granteeEmail)
{
// Arrange
var logger = Substitute.For>();
@@ -41,7 +41,7 @@ public class EmergencyAccessMailTests
ToEmails = [grantorEmail],
View = new EmergencyAccessRemoveGranteesMailView
{
- RemovedGranteeEmails = [granteeName]
+ RemovedGranteeEmails = [granteeEmail]
}
};
@@ -58,8 +58,8 @@ public class EmergencyAccessMailTests
Assert.Contains(grantorEmail, sentMessage.ToEmails);
// Verify the content contains the grantee name
- Assert.Contains(granteeName, sentMessage.TextContent);
- Assert.Contains(granteeName, sentMessage.HtmlContent);
+ Assert.Contains(granteeEmail, sentMessage.TextContent);
+ Assert.Contains(granteeEmail, sentMessage.HtmlContent);
}
///
@@ -77,14 +77,14 @@ public class EmergencyAccessMailTests
new HandlebarMailRenderer(logger, globalSettings),
deliveryService);
- var granteeNames = new[] { "Alice", "Bob", "Carol" };
+ var granteeEmails = new[] { "Alice@test.dev", "Bob@test.dev", "Carol@test.dev" };
var mail = new EmergencyAccessRemoveGranteesMail
{
ToEmails = [grantorEmail],
View = new EmergencyAccessRemoveGranteesMailView
{
- RemovedGranteeEmails = granteeNames
+ RemovedGranteeEmails = granteeEmails
}
};
@@ -98,10 +98,10 @@ public class EmergencyAccessMailTests
// Assert - All grantee names should appear in the email
Assert.NotNull(sentMessage);
- foreach (var granteeName in granteeNames)
+ foreach (var granteeEmail in granteeEmails)
{
- Assert.Contains(granteeName, sentMessage.TextContent);
- Assert.Contains(granteeName, sentMessage.HtmlContent);
+ Assert.Contains(granteeEmail, sentMessage.TextContent);
+ Assert.Contains(granteeEmail, sentMessage.HtmlContent);
}
}
@@ -148,6 +148,6 @@ public class EmergencyAccessMailTests
Assert.NotNull(mail);
Assert.NotNull(mail.View);
Assert.Equal(_emergencyAccessMailSubject, mail.Subject);
- Assert.Equal(_emergencyAccessHelpUrl, EmergencyAccessRemoveGranteesMailView.EmergencyAccessHelpPageUrl);
+ Assert.Equal(_emergencyAccessHelpUrl, mail.View.EmergencyAccessHelpPageUrl);
}
}