diff --git a/src/Umbraco.Infrastructure/Security/MemberUserStore.cs b/src/Umbraco.Infrastructure/Security/MemberUserStore.cs index 1d871e4134..c0e4373826 100644 --- a/src/Umbraco.Infrastructure/Security/MemberUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/MemberUserStore.cs @@ -21,6 +21,7 @@ namespace Umbraco.Cms.Core.Security /// public class MemberUserStore : UserStoreBase, IdentityUserRole, IdentityUserLogin, IdentityUserToken, IdentityRoleClaim> { + private const string genericIdentityErrorCode = "IdentityErrorUserStore"; private readonly IMemberService _memberService; private readonly UmbracoMapper _mapper; private readonly IScopeProvider _scopeProvider; @@ -49,10 +50,10 @@ namespace Umbraco.Cms.Core.Security public override IQueryable Users => throw new NotImplementedException(); /// - public override Task GetNormalizedUserNameAsync(MemberIdentityUser user, CancellationToken cancellationToken) => GetUserNameAsync(user, cancellationToken); + public override Task GetNormalizedUserNameAsync(MemberIdentityUser user, CancellationToken cancellationToken = default) => GetUserNameAsync(user, cancellationToken); /// - public override Task SetNormalizedUserNameAsync(MemberIdentityUser user, string normalizedName, CancellationToken cancellationToken) => SetUserNameAsync(user, normalizedName, cancellationToken); + public override Task SetNormalizedUserNameAsync(MemberIdentityUser user, string normalizedName, CancellationToken cancellationToken = default) => SetUserNameAsync(user, normalizedName, cancellationToken); /// public override Task CreateAsync(MemberIdentityUser user, CancellationToken cancellationToken = default) @@ -104,7 +105,7 @@ namespace Umbraco.Cms.Core.Security } catch (Exception ex) { - return Task.FromResult(IdentityResult.Failed(new IdentityError { Code = ex.Message, Description = ex.Message })); + return Task.FromResult(IdentityResult.Failed(new IdentityError { Code = genericIdentityErrorCode, Description = ex.Message })); } } @@ -160,7 +161,7 @@ namespace Umbraco.Cms.Core.Security } catch (Exception ex) { - return Task.FromResult(IdentityResult.Failed(new IdentityError { Code = ex.Message, Description = ex.Message })); + return Task.FromResult(IdentityResult.Failed(new IdentityError { Code = genericIdentityErrorCode, Description = ex.Message })); } } @@ -189,7 +190,7 @@ namespace Umbraco.Cms.Core.Security } catch (Exception ex) { - return Task.FromResult(IdentityResult.Failed(new IdentityError { Code = ex.Message, Description = ex.Message })); + return Task.FromResult(IdentityResult.Failed(new IdentityError { Code = genericIdentityErrorCode, Description = ex.Message })); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Security/MemberIdentityUserStoreTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Security/MemberIdentityUserStoreTests.cs index a56b794ffb..5d9303b908 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Security/MemberIdentityUserStoreTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Security/MemberIdentityUserStoreTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -31,19 +32,127 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Security } [Test] - public void GivenICreateUser_AndTheUserIsNull_ThenIShouldGetAFailedResultAsync() + public void GivenIGetNormalizedUserName_AndTheUserIsNull_ThenIShouldGetAnException() { // arrange MemberUserStore sut = CreateSut(); CancellationToken fakeCancellationToken = new CancellationToken() { }; // act - Action actual = () => sut.CreateAsync(null, fakeCancellationToken); + Action actual = () => sut.GetNormalizedUserNameAsync(null, fakeCancellationToken); // assert Assert.That(actual, Throws.ArgumentNullException); } + [Test] + public async Task GivenIGetNormalizedUserName_AndTheEverythingIsPopulatedCorrectly_ThenIShouldGetACorrectUsername() + { + // arrange + MemberUserStore sut = CreateSut(); + var fakeUser = new MemberIdentityUser() + { + UserName = "fakeuser" + }; + + // act + string actual = await sut.GetNormalizedUserNameAsync(fakeUser); + + // assert + Assert.AreEqual(actual, fakeUser.UserName); + } + + [Test] + public void GivenISetNormalizedUserName_AndTheUserIsNull_ThenIShouldGetAnException() + { + // arrange + MemberUserStore sut = CreateSut(); + CancellationToken fakeCancellationToken = new CancellationToken() { }; + + // act + Action actual = () => sut.SetNormalizedUserNameAsync(null, "username", fakeCancellationToken); + + // assert + Assert.That(actual, Throws.ArgumentNullException); + } + + + [Test] + public void GivenISetNormalizedUserName_AndTheUserNameIsNull_ThenIShouldGetANull() + { + // arrange + MemberUserStore sut = CreateSut(); + CancellationToken fakeCancellationToken = new CancellationToken() { }; + var fakeUser = new MemberIdentityUser() { }; + + // act + Task actual = sut.SetNormalizedUserNameAsync(fakeUser, null, fakeCancellationToken); + + // assert + Assert.AreEqual(null, actual); + } + + [Test] + public void GivenISetNormalizedUserName_AndEverythingIsPopulated_ThenIShouldGetASuccessResult() + { + // arrange + MemberUserStore sut = CreateSut(); + CancellationToken fakeCancellationToken = new CancellationToken() { }; + var fakeUser = new MemberIdentityUser() + { + UserName = "MyName" + }; + + // act + Task actual = sut.SetNormalizedUserNameAsync(fakeUser, "NewName", fakeCancellationToken); + + // assert + Assert.IsTrue(actual.IsCompletedSuccessfully); + } + + [Test] + public async Task GivenICreateUser_AndTheUserIsNull_ThenIShouldGetAFailedResultAsync() + { + // arrange + MemberUserStore sut = CreateSut(); + + // act + IdentityResult actual = await sut.CreateAsync(null); + + // assert + Assert.IsFalse(actual.Succeeded); + Assert.IsTrue(actual.Errors.Any(x => x.Code == "IdentityErrorUserStore" && x.Description == "Value cannot be null. (Parameter 'user')")); + _mockMemberService.VerifyNoOtherCalls(); + } + + [Test] + public async Task GivenICreateUser_AndTheUserDoesNotHaveIdentity_ThenIShouldGetAFailedResultAsync() + { + // arrange + MemberUserStore sut = CreateSut(); + var fakeUser = new MemberIdentityUser() { }; + var fakeCancellationToken = new CancellationToken() { }; + + IMemberType fakeMemberType = new MemberType(new MockShortStringHelper(), 77); + IMember mockMember = Mock.Of(m => + m.Name == "fakeName" && + m.Email == "fakeemail@umbraco.com" && + m.Username == "fakeUsername" && + m.RawPasswordValue == "fakePassword" && + m.ContentTypeAlias == fakeMemberType.Alias && + m.HasIdentity == false); + + _mockMemberService.Setup(x => x.CreateMember(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(mockMember); + _mockMemberService.Setup(x => x.Save(mockMember, It.IsAny())); + + // act + IdentityResult actual = await sut.CreateAsync(null); + + // assert + Assert.IsFalse(actual.Succeeded); + Assert.IsTrue(actual.Errors.Any(x => x.Code == "IdentityErrorUserStore" && x.Description == "Value cannot be null. (Parameter 'user')")); + _mockMemberService.VerifyNoOtherCalls(); + } [Test] public async Task GivenICreateANewUser_AndTheUserIsPopulatedCorrectly_ThenIShouldGetASuccessResultAsync() @@ -85,10 +194,11 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Security MemberUserStore sut = CreateSut(); // act - Action actual = () => sut.DeleteAsync(null); + IdentityResult actual = await sut.DeleteAsync(null); // assert - Assert.That(actual, Throws.ArgumentNullException); + Assert.IsTrue(actual.Succeeded == false); + Assert.IsTrue(actual.Errors.Any(x => x.Code == "IdentityErrorUserStore" && x.Description == "Value cannot be null. (Parameter 'user')")); _mockMemberService.VerifyNoOtherCalls(); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Security/MemberRoleStoreTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Security/MemberRoleStoreTests.cs index 3b78bc1b39..e6bb0b9ff5 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Security/MemberRoleStoreTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Security/MemberRoleStoreTests.cs @@ -26,17 +26,18 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Security } [Test] - public void GivenICreateAMemberRole_AndTheGroupIsNull_ThenIShouldGetAnArgumentException() + public void GivenICreateAMemberRole_AndTheGroupIsNull_ThenIShouldGetAFailedIdentityResult() { // arrange MemberRoleStore sut = CreateSut(); CancellationToken fakeCancellationToken = new CancellationToken() { }; // act - Action actual = () => sut.CreateAsync(null, fakeCancellationToken); + Task actual = sut.CreateAsync(null, fakeCancellationToken); // assert - Assert.That(actual, Throws.ArgumentNullException); + Assert.IsTrue(actual.Result.Succeeded == false); + Assert.IsTrue(actual.Result.Errors.Any(x => x.Code == "IdentityMemberGroupNotFound" && x.Description == "Member group not found")); } @@ -139,15 +140,12 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Security }; var fakeCancellationToken = new CancellationToken() { }; - bool raiseEvents = false; - - // act IdentityResult identityResult = await sut.UpdateAsync(fakeRole, fakeCancellationToken); // assert Assert.IsTrue(identityResult.Succeeded == false); - Assert.IsTrue(identityResult.Errors.Any(x => x.Code == "InvalidRoleName" && x.Description == "Role name 'testname' is invalid.")); + Assert.IsTrue(identityResult.Errors.Any(x => x.Code == "IdentityMemberGroupNotFound" && x.Description == "Member group not found")); _mockMemberGroupService.Verify(x => x.GetById(777)); } @@ -168,7 +166,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Security // assert Assert.IsTrue(identityResult.Succeeded == false); - Assert.IsTrue(identityResult.Errors.Any(x => x.Code == "DefaultError" && x.Description == "An unknown failure has occurred.")); + Assert.IsTrue(identityResult.Errors.Any(x => x.Code == "IdentityIdParseError" && x.Description == "Cannot parse ID to int")); _mockMemberGroupService.VerifyNoOtherCalls(); } @@ -221,7 +219,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Security // assert Assert.IsTrue(identityResult.Succeeded == false); - Assert.IsTrue(identityResult.Errors.Any(x => x.Code == "DefaultError" && x.Description == "An unknown failure has occurred.")); + Assert.IsTrue(identityResult.Errors.Any(x => x.Code == "IdentityIdParseError" && x.Description == "Cannot parse ID to int")); _mockMemberGroupService.VerifyNoOtherCalls(); } @@ -247,7 +245,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Security // assert Assert.IsTrue(identityResult.Succeeded == false); - Assert.IsTrue(identityResult.Errors.Any(x => x.Code == "InvalidRoleName" && x.Description == "Role name 'testname' is invalid.")); + Assert.IsTrue(identityResult.Errors.Any(x => x.Code == "IdentityMemberGroupNotFound" && x.Description == "Member group not found")); _mockMemberGroupService.Verify(x => x.GetById(777)); _mockMemberGroupService.VerifyNoOtherCalls(); } @@ -283,7 +281,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Security } [Test] - public void GivenIFindAMemberRoleByRoleId_AndIdCannotBeParsedToAnInt_ThenIShouldGetAFailureResultAsync() + public async Task GivenIFindAMemberRoleByRoleId_AndIdCannotBeParsedToAnInt_ThenIShouldGetAFailureResultAsync() { // arrange MemberRoleStore sut = CreateSut(); @@ -295,10 +293,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Security var fakeCancellationToken = new CancellationToken() { }; // act - Task actual = sut.FindByIdAsync(fakeRole.Id, fakeCancellationToken); + Action actual = () => sut.FindByIdAsync(fakeRole.Id, fakeCancellationToken); // assert - Assert.IsNull(actual); + Assert.That(actual, Throws.TypeOf()); _mockMemberGroupService.VerifyNoOtherCalls(); }