From 936555339fe6b42efcc4fa205cc9c4b5ea04a06d Mon Sep 17 00:00:00 2001 From: James Gunn Date: Mon, 18 Nov 2024 09:41:07 +0000 Subject: [PATCH] Add the calling app's name to TRN allocation tasks (#1684) --- .../ServiceCollectionExtensions.cs | 2 +- .../ClaimsPrincipalCurrentUserProvider.cs | 18 +-- .../Security/ICurrentUserProvider.cs | 2 +- .../Handlers/GetOrCreateTrnRequestHandler.cs | 2 +- .../V2/Handlers/GetTrnRequestHandler.cs | 2 +- .../V3/Core/Operations/CreateTrnRequest.cs | 3 +- .../V3/Core/Operations/GetTrnRequest.cs | 2 +- .../Dqt/Queries/CreateTeacherQuery.cs | 1 + .../Dqt/QueryHandlers/CreateContactHandler.cs | 106 ++++++++-------- .../QueryTests/CreateContactTests.cs | 113 +++++------------- 10 files changed, 104 insertions(+), 147 deletions(-) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/RateLimiting/ServiceCollectionExtensions.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/RateLimiting/ServiceCollectionExtensions.cs index 1caeef0f8..c4c1657bb 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/RateLimiting/ServiceCollectionExtensions.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/RateLimiting/ServiceCollectionExtensions.cs @@ -52,7 +52,7 @@ public static IServiceCollection AddRateLimiting( { var rateLimiterOptions = httpContext.RequestServices.GetRequiredService>().Value; var connectionMultiplexerFactory = () => httpContext.RequestServices.GetRequiredService(); - var partitionKey = ClaimsPrincipalCurrentUserProvider.TryGetCurrentClientIdFromHttpContext(httpContext, out var userId) ? userId.ToString() : UnknownUserPartitionKey; + var partitionKey = ClaimsPrincipalCurrentUserProvider.TryGetCurrentApplicationUserFromHttpContext(httpContext, out var userId) ? userId.ToString() : UnknownUserPartitionKey; var clientRateLimit = rateLimiterOptions.ClientRateLimits.TryGetValue(partitionKey, out var windowOptions) ? windowOptions : rateLimiterOptions.DefaultRateLimit; // Window isn't available via RateLimitMetadata so stash it on the HttpContext instead diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Security/ClaimsPrincipalCurrentUserProvider.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Security/ClaimsPrincipalCurrentUserProvider.cs index 62bebf47a..ab87a6615 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Security/ClaimsPrincipalCurrentUserProvider.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Security/ClaimsPrincipalCurrentUserProvider.cs @@ -4,28 +4,30 @@ namespace TeachingRecordSystem.Api.Infrastructure.Security; public class ClaimsPrincipalCurrentUserProvider(IHttpContextAccessor httpContextAccessor) : ICurrentUserProvider { - public static bool TryGetCurrentClientIdFromHttpContext(HttpContext httpContext, out Guid userId) + public static bool TryGetCurrentApplicationUserFromHttpContext(HttpContext httpContext, out (Guid UserId, string Name) user) { var userIdStr = httpContext.User.FindFirstValue("sub"); + var name = httpContext.User.FindFirstValue(ClaimTypes.Name); - if (userIdStr is null) + if (userIdStr is null || !Guid.TryParse(userIdStr, out var userId) || name is null) { - userId = default; + user = default; return false; } - return Guid.TryParse(userIdStr, out userId); + user = (UserId: userId, Name: name); + return true; } - public Guid GetCurrentApplicationUserId() + public (Guid UserId, string Name) GetCurrentApplicationUser() { var httpContext = httpContextAccessor.HttpContext ?? throw new Exception("No HttpContext."); - if (!TryGetCurrentClientIdFromHttpContext(httpContext, out var userId)) + if (!TryGetCurrentApplicationUserFromHttpContext(httpContext, out var user)) { - throw new Exception("Current user has no 'sub' claim."); + throw new Exception("No current user."); } - return userId; + return user; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Security/ICurrentUserProvider.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Security/ICurrentUserProvider.cs index ce38d7d1f..fdaa61388 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Security/ICurrentUserProvider.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Security/ICurrentUserProvider.cs @@ -2,5 +2,5 @@ namespace TeachingRecordSystem.Api.Infrastructure.Security; public interface ICurrentUserProvider { - Guid GetCurrentApplicationUserId(); + (Guid UserId, string Name) GetCurrentApplicationUser(); } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V2/Handlers/GetOrCreateTrnRequestHandler.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V2/Handlers/GetOrCreateTrnRequestHandler.cs index 2beb598be..5b4920a1d 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V2/Handlers/GetOrCreateTrnRequestHandler.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V2/Handlers/GetOrCreateTrnRequestHandler.cs @@ -46,7 +46,7 @@ public GetOrCreateTrnRequestHandler( public async Task Handle(GetOrCreateTrnRequest request, CancellationToken cancellationToken) { - var currentApplicationUserId = _currentUserProvider.GetCurrentApplicationUserId(); + var (currentApplicationUserId, _) = _currentUserProvider.GetCurrentApplicationUser(); await using var requestIdLock = await _distributedLockProvider.AcquireLockAsync( DistributedLockKeys.TrnRequestId(currentApplicationUserId, request.RequestId), diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V2/Handlers/GetTrnRequestHandler.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V2/Handlers/GetTrnRequestHandler.cs index 9b5f3fdcc..11a8cb3af 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V2/Handlers/GetTrnRequestHandler.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V2/Handlers/GetTrnRequestHandler.cs @@ -32,7 +32,7 @@ public GetTrnRequestHandler( public async Task Handle(GetTrnRequest request, CancellationToken cancellationToken) { - var currentApplicationUserId = _currentUserProvider.GetCurrentApplicationUserId(); + var (currentApplicationUserId, _) = _currentUserProvider.GetCurrentApplicationUser(); var trnRequest = await _trnRequestHelper.GetTrnRequestInfo(currentApplicationUserId, request.RequestId); if (trnRequest == null) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/CreateTrnRequest.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/CreateTrnRequest.cs index cf7690321..94d3d6b46 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/CreateTrnRequest.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/CreateTrnRequest.cs @@ -39,7 +39,7 @@ public class CreateTrnRequestHandler( { public async Task Handle(CreateTrnRequestCommand command) { - var currentApplicationUserId = currentUserProvider.GetCurrentApplicationUserId(); + var (currentApplicationUserId, currentApplicationUserName) = currentUserProvider.GetCurrentApplicationUser(); var trnRequest = await trnRequestHelper.GetTrnRequestInfo(currentApplicationUserId, command.RequestId); if (trnRequest is not null) @@ -147,6 +147,7 @@ await crmQueryDispatcher.ExecuteQuery(new CreateContactQuery() EmailAddress = emailAddress, NationalInsuranceNumber = NationalInsuranceNumberHelper.Normalize(command.NationalInsuranceNumber), PotentialDuplicates = potentialDuplicates.Select(d => (Duplicate: d, HasActiveAlert: resultsWithActiveAlerts.Contains(d.ContactId))).ToArray(), + ApplicationUserName = currentApplicationUserName, Trn = trn, TrnRequestId = TrnRequestHelper.GetCrmTrnRequestId(currentApplicationUserId, command.RequestId), OutboxMessages = outboxMessages diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/GetTrnRequest.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/GetTrnRequest.cs index ff9ccffbd..45948c669 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/GetTrnRequest.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/GetTrnRequest.cs @@ -10,7 +10,7 @@ public class GetTrnRequestHandler(TrnRequestHelper trnRequestHelper, ICurrentUse { public async Task Handle(GetTrnRequestCommand command) { - var currentApplicationUserId = currentUserProvider.GetCurrentApplicationUserId(); + var (currentApplicationUserId, _) = currentUserProvider.GetCurrentApplicationUser(); var trnRequest = await trnRequestHelper.GetTrnRequestInfo(currentApplicationUserId, command.RequestId); if (trnRequest is null) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/CreateTeacherQuery.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/CreateTeacherQuery.cs index 602cbd1b8..f6707ef69 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/CreateTeacherQuery.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/CreateTeacherQuery.cs @@ -12,6 +12,7 @@ public class CreateContactQuery : ICrmQuery public required string? EmailAddress { get; init; } public required string? NationalInsuranceNumber { get; init; } public required IReadOnlyCollection<(FindPotentialDuplicateContactsResult Duplicate, bool HasActiveAlert)> PotentialDuplicates { get; init; } + public required string ApplicationUserName { get; init; } public required string? Trn { get; init; } public required string? TrnRequestId { get; init; } public required IEnumerable OutboxMessages { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/CreateContactHandler.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/CreateContactHandler.cs index 401d4a460..88d24e795 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/CreateContactHandler.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/CreateContactHandler.cs @@ -33,11 +33,17 @@ public async Task Execute(CreateContactQuery query, IOrganizationServiceAs dfeta_TRN = query.Trn }; + if (query.Trn is null) + { + // CRM plug-in explodes if TRN is specified but is null + contact.Attributes.Remove(Contact.Fields.dfeta_TRN); + } + requestBuilder.AddRequest(new CreateRequest() { Target = contact }); foreach (var (duplicate, hasActiveAlert) in query.PotentialDuplicates) { - var task = CreateDuplicateReviewTaskEntity(duplicate, contactId, hasActiveAlert); + var task = CreateDuplicateReviewTaskEntity(duplicate, hasActiveAlert); requestBuilder.AddRequest(new CreateRequest() { Target = task }); } @@ -49,66 +55,66 @@ public async Task Execute(CreateContactQuery query, IOrganizationServiceAs await requestBuilder.Execute(); return contactId; - } - - private CrmTask CreateDuplicateReviewTaskEntity(FindPotentialDuplicateContactsResult duplicate, Guid contactId, bool hasActiveAlert) - { - var description = GetDescription(); - - var category = "DMSImportTrn"; - return new CrmTask() + CrmTask CreateDuplicateReviewTaskEntity(FindPotentialDuplicateContactsResult duplicate, bool hasActiveAlert) { - RegardingObjectId = contactId.ToEntityReference(Contact.EntityLogicalName), - dfeta_potentialduplicateid = duplicate.ContactId.ToEntityReference(Contact.EntityLogicalName), - Category = category, - Subject = "Notification for QTS Unit Team", - Description = description - }; + var description = GetDescription(); - string GetDescription() - { - var sb = new StringBuilder(); - sb.AppendLine("Potential duplicate"); - sb.AppendLine("Matched on"); + var category = $"TRN request from {query.ApplicationUserName}"; - foreach (var matchedAttribute in duplicate.MatchedAttributes) + return new CrmTask() { - sb.AppendLine(matchedAttribute switch - { - Contact.Fields.FirstName => $" - First name: '{duplicate.FirstName}'", - Contact.Fields.MiddleName => $" - Middle name: '{duplicate.MiddleName}'", - Contact.Fields.LastName => $" - Last name: '{duplicate.LastName}'", - Contact.Fields.BirthDate => $" - Date of birth: '{duplicate.DateOfBirth:dd/MM/yyyy}'", - Contact.Fields.dfeta_NINumber => $" - National Insurance number: '{duplicate.NationalInsuranceNumber}'", - Contact.Fields.EMailAddress1 => $" - Email address: '{duplicate.EmailAddress}'", - _ => throw new Exception($"Unknown matched field: '{matchedAttribute}'.") - }); - } + RegardingObjectId = contactId.ToEntityReference(Contact.EntityLogicalName), + dfeta_potentialduplicateid = duplicate.ContactId.ToEntityReference(Contact.EntityLogicalName), + Category = category, + Subject = "Notification for QTS Unit Team", + Description = description + }; + + string GetDescription() + { + var sb = new StringBuilder(); + sb.AppendLine("Potential duplicate"); + sb.AppendLine("Matched on"); - var additionalFlags = new List(); + foreach (var matchedAttribute in duplicate.MatchedAttributes) + { + sb.AppendLine(matchedAttribute switch + { + Contact.Fields.FirstName => $" - First name: '{duplicate.FirstName}'", + Contact.Fields.MiddleName => $" - Middle name: '{duplicate.MiddleName}'", + Contact.Fields.LastName => $" - Last name: '{duplicate.LastName}'", + Contact.Fields.BirthDate => $" - Date of birth: '{duplicate.DateOfBirth:dd/MM/yyyy}'", + Contact.Fields.dfeta_NINumber => $" - National Insurance number: '{duplicate.NationalInsuranceNumber}'", + Contact.Fields.EMailAddress1 => $" - Email address: '{duplicate.EmailAddress}'", + _ => throw new Exception($"Unknown matched field: '{matchedAttribute}'.") + }); + } + + var additionalFlags = new List(); + + if (hasActiveAlert) + { + additionalFlags.Add("active sanctions"); + } - if (hasActiveAlert) - { - additionalFlags.Add("active sanctions"); - } + if (duplicate.HasQtsDate) + { + additionalFlags.Add("QTS date"); + } - if (duplicate.HasQtsDate) - { - additionalFlags.Add("QTS date"); - } + if (duplicate.HasEytsDate) + { + additionalFlags.Add("EYTS date"); + } - if (duplicate.HasEytsDate) - { - additionalFlags.Add("EYTS date"); - } + if (additionalFlags.Count > 0) + { + sb.AppendLine($"Matched record has {string.Join(" & ", additionalFlags)}"); + } - if (additionalFlags.Count > 0) - { - sb.AppendLine($"Matched record has {string.Join(" & ", additionalFlags)}"); + return sb.ToString(); } - - return sb.ToString(); } } } diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Dqt.CrmIntegrationTests/QueryTests/CreateContactTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Dqt.CrmIntegrationTests/QueryTests/CreateContactTests.cs index b2f1323b0..175c87fdb 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Dqt.CrmIntegrationTests/QueryTests/CreateContactTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Dqt.CrmIntegrationTests/QueryTests/CreateContactTests.cs @@ -25,8 +25,8 @@ public async Task QueryExecutesSuccessfully() var middleName = _dataScope.TestData.GenerateMiddleName(); var lastName = _dataScope.TestData.GenerateLastName(); var email = _dataScope.TestData.GenerateUniqueEmail(); - var ni = _dataScope.TestData.GenerateNationalInsuranceNumber(); - var dob = _dataScope.TestData.GenerateDateOfBirth(); + var nino = _dataScope.TestData.GenerateNationalInsuranceNumber(); + var dateOfBirth = _dataScope.TestData.GenerateDateOfBirth(); var trn = await _dataScope.TestData.GenerateTrn(); var query = new CreateContactQuery() @@ -39,10 +39,11 @@ public async Task QueryExecutesSuccessfully() StatedMiddleName = middleName, StatedLastName = lastName, EmailAddress = email, - NationalInsuranceNumber = ni, - DateOfBirth = dob, + NationalInsuranceNumber = nino, + DateOfBirth = dateOfBirth, Trn = trn, PotentialDuplicates = [], + ApplicationUserName = "Tests", OutboxMessages = [] }; @@ -59,53 +60,8 @@ public async Task QueryExecutesSuccessfully() Assert.Equal(lastName, contact.LastName); Assert.Equal(email, contact.EMailAddress1); Assert.False(contact.dfeta_AllowPiiUpdatesFromRegister); - Assert.Equal(ni, contact.dfeta_NINumber); - Assert.Equal(dob, contact.BirthDate.ToDateOnlyWithDqtBstFix(true)); - } - - [Theory] - [InlineData("1", "", "", "First name contains a digit")] - [InlineData("", "1", "", "Middle name contains a digit")] - [InlineData("", "", "1", "Last name contains a digit")] - public async Task QueryWithDigits_ExecutesSuccessfully_CreatesTask(string firstNameStr, string middleNameStr, string lastNameStr, string description) - { - // Arrange - var firstName = $"{_dataScope.TestData.GenerateFirstName()}{firstNameStr}"; - var middleName = $"{_dataScope.TestData.GenerateMiddleName()}{middleNameStr}"; - var lastName = $"{_dataScope.TestData.GenerateLastName()}{lastNameStr}"; - var email = _dataScope.TestData.GenerateUniqueEmail(); - var ni = _dataScope.TestData.GenerateNationalInsuranceNumber(); - var dob = _dataScope.TestData.GenerateDateOfBirth(); - var trn = await _dataScope.TestData.GenerateTrn(); - - var query = new CreateContactQuery() - { - TrnRequestId = null, - FirstName = firstName, - MiddleName = middleName, - LastName = lastName, - StatedFirstName = firstName, - StatedMiddleName = middleName, - StatedLastName = lastName, - EmailAddress = email, - NationalInsuranceNumber = ni, - DateOfBirth = dob, - Trn = trn, - PotentialDuplicates = [], - OutboxMessages = [] - }; - - // Act - var createdTeacherId = await _crmQueryDispatcher.ExecuteQuery(query); - - // Assert - using var ctx = new DqtCrmServiceContext(_dataScope.OrganizationService); - var contact = ctx.ContactSet.SingleOrDefault(i => i.GetAttributeValue(Contact.PrimaryIdAttribute) == createdTeacherId); - var task = ctx.TaskSet.FirstOrDefault(x => x.RegardingObjectId == createdTeacherId.ToEntityReference(Contact.EntityLogicalName)); - Assert.NotNull(contact); - Assert.NotNull(task); - Assert.Equal(description, task.Description); - Assert.Equal("DMSImportTrn", task.Category); + Assert.Equal(nino, contact.dfeta_NINumber); + Assert.Equal(dateOfBirth, contact.BirthDate.ToDateOnlyWithDqtBstFix(true)); } [Fact] @@ -116,31 +72,23 @@ public async Task QueryWithMatchedDuplicateContactName_ExecutesSuccessfully_Crea var middleName = $"{_dataScope.TestData.GenerateMiddleName()}"; var lastName = $"{_dataScope.TestData.GenerateLastName()}"; var email = _dataScope.TestData.GenerateUniqueEmail(); - var ni = _dataScope.TestData.GenerateNationalInsuranceNumber(); - var dob = _dataScope.TestData.GenerateDateOfBirth(); - var trn1 = await _dataScope.TestData.GenerateTrn(); - var trn2 = await _dataScope.TestData.GenerateTrn(); + var nino = _dataScope.TestData.GenerateNationalInsuranceNumber(); + var dateOfBirth = _dataScope.TestData.GenerateDateOfBirth(); - var query1 = new CreateContactQuery() + var existingContactId = Guid.NewGuid(); + var existingContactTrn = await _dataScope.TestData.GenerateTrn(); + await _dataScope.OrganizationService.CreateAsync(new Contact() { - TrnRequestId = null, + Id = existingContactId, FirstName = firstName, MiddleName = middleName, LastName = lastName, - StatedFirstName = firstName, - StatedMiddleName = middleName, - StatedLastName = lastName, - EmailAddress = email, - NationalInsuranceNumber = ni, - DateOfBirth = dob, - Trn = trn1, - PotentialDuplicates = [], - OutboxMessages = [] - }; + BirthDate = dateOfBirth.ToDateTimeWithDqtBstFix(isLocalTime: false), + dfeta_TRN = existingContactTrn + }); // Act - var createdTeacherId1 = await _crmQueryDispatcher.ExecuteQuery(query1); - var query2 = new CreateContactQuery() + var query = new CreateContactQuery() { TrnRequestId = null, FirstName = firstName, @@ -150,15 +98,15 @@ public async Task QueryWithMatchedDuplicateContactName_ExecutesSuccessfully_Crea StatedMiddleName = middleName, StatedLastName = lastName, EmailAddress = email, - NationalInsuranceNumber = ni, - DateOfBirth = dob, - Trn = trn2, + NationalInsuranceNumber = nino, + DateOfBirth = dateOfBirth, + Trn = null, PotentialDuplicates = [ (Duplicate: new FindPotentialDuplicateContactsResult() { - ContactId = createdTeacherId1, - Trn = trn1, + ContactId = existingContactId, + Trn = existingContactTrn, MatchedAttributes = [Contact.Fields.FirstName, Contact.Fields.MiddleName, Contact.Fields.LastName], HasEytsDate = false, HasQtsDate = false, @@ -168,26 +116,25 @@ public async Task QueryWithMatchedDuplicateContactName_ExecutesSuccessfully_Crea StatedFirstName = firstName, StatedMiddleName = middleName, StatedLastName = lastName, - DateOfBirth = dob, + DateOfBirth = dateOfBirth, EmailAddress = email, - NationalInsuranceNumber = ni + NationalInsuranceNumber = nino }, HasActiveAlert: false) ], + ApplicationUserName = "Tests", OutboxMessages = [] }; - var createdTeacherId2 = await _crmQueryDispatcher.ExecuteQuery(query2); + var createdTeacherId2 = await _crmQueryDispatcher.ExecuteQuery(query); using var ctx = new DqtCrmServiceContext(_dataScope.OrganizationService); - var contact1 = ctx.ContactSet.SingleOrDefault(i => i.GetAttributeValue(Contact.PrimaryIdAttribute) == createdTeacherId1); - var contact2 = ctx.ContactSet.SingleOrDefault(i => i.GetAttributeValue(Contact.PrimaryIdAttribute) == createdTeacherId2); + var contact = ctx.ContactSet.SingleOrDefault(i => i.GetAttributeValue(Contact.PrimaryIdAttribute) == createdTeacherId2); var potentialDuplicateTask = ctx.TaskSet.FirstOrDefault(x => x.RegardingObjectId == createdTeacherId2.ToEntityReference(Contact.EntityLogicalName)); // Assert - Assert.NotNull(contact1); - Assert.NotNull(contact2); - Assert.Null(contact2.dfeta_TRN); + Assert.NotNull(contact); + Assert.Null(contact.dfeta_TRN); Assert.NotNull(potentialDuplicateTask); Assert.Contains("Potential duplicate", potentialDuplicateTask.Description); - Assert.Equal("DMSImportTrn", potentialDuplicateTask.Category); + Assert.Equal("TRN request from Tests", potentialDuplicateTask.Category); } }