From ef9b22e3df7303f78e577f1ac3c9e8211accaeb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= Date: Tue, 25 Dec 2018 19:13:42 +0100 Subject: [PATCH 1/2] Extending BulkDeleteRequest by adding synchronous Delete Adding UnitTest --- .../BulkDeleteRequestExecutor.cs | 59 +++++++ .../FakeXrmEasy.Shared.projitems | 1 + .../BulkDeleteRequestTests.cs | 167 ++++++++++++++++++ .../FakeXrmEasy.Tests.Shared.projitems | 1 + 4 files changed, 228 insertions(+) create mode 100644 FakeXrmEasy.Shared/FakeMessageExecutors/BulkDeleteRequestExecutor.cs create mode 100644 FakeXrmEasy.Tests.Shared/FakeContextTests/BulkDeleteRequestTests/BulkDeleteRequestTests.cs diff --git a/FakeXrmEasy.Shared/FakeMessageExecutors/BulkDeleteRequestExecutor.cs b/FakeXrmEasy.Shared/FakeMessageExecutors/BulkDeleteRequestExecutor.cs new file mode 100644 index 00000000..a38cf81d --- /dev/null +++ b/FakeXrmEasy.Shared/FakeMessageExecutors/BulkDeleteRequestExecutor.cs @@ -0,0 +1,59 @@ +using System; +using System.ServiceModel; +using Microsoft.Crm.Sdk.Messages; +using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Query; + +namespace FakeXrmEasy.FakeMessageExecutors +{ + public class BulkDeleteRequestExecutor : IFakeMessageExecutor + { + public bool CanExecute(OrganizationRequest request) + { + return request is BulkDeleteRequest; + } + + public OrganizationResponse Execute(OrganizationRequest request, XrmFakedContext ctx) + { + var bulkDeleteRequest = (BulkDeleteRequest)request; + + if (string.IsNullOrEmpty(bulkDeleteRequest.JobName)) + { + throw new FaultException(new OrganizationServiceFault(), "Can not Bulk delete without JobName"); + } + if (bulkDeleteRequest.QuerySet == null) + { + throw new FaultException(new OrganizationServiceFault(), "Can not Bulk delete without QuerySet"); + } + if (bulkDeleteRequest.CCRecipients == null) + { + throw new FaultException(new OrganizationServiceFault(), "Can not Bulk delete without CCRecipients"); + } + if (bulkDeleteRequest.ToRecipients == null) + { + throw new FaultException(new OrganizationServiceFault(), "Can not Bulk delete without ToRecipients"); + } + + var service = ctx.GetOrganizationService(); + + foreach (QueryExpression queryExpression in bulkDeleteRequest.QuerySet) + { + EntityCollection recordsToDelete = service.RetrieveMultiple(queryExpression); + foreach (Entity record in recordsToDelete.Entities) + { + service.Delete(record.LogicalName, record.Id); + } + } + + return new BulkDeleteResponse() + { + ResponseName = "BulkDeleteResponse" + }; + } + + public Type GetResponsibleRequestType() + { + return typeof(BulkDeleteRequest); + } + } +} diff --git a/FakeXrmEasy.Shared/FakeXrmEasy.Shared.projitems b/FakeXrmEasy.Shared/FakeXrmEasy.Shared.projitems index 6700973f..d946e4a3 100644 --- a/FakeXrmEasy.Shared/FakeXrmEasy.Shared.projitems +++ b/FakeXrmEasy.Shared/FakeXrmEasy.Shared.projitems @@ -19,6 +19,7 @@ + diff --git a/FakeXrmEasy.Tests.Shared/FakeContextTests/BulkDeleteRequestTests/BulkDeleteRequestTests.cs b/FakeXrmEasy.Tests.Shared/FakeContextTests/BulkDeleteRequestTests/BulkDeleteRequestTests.cs new file mode 100644 index 00000000..3056d900 --- /dev/null +++ b/FakeXrmEasy.Tests.Shared/FakeContextTests/BulkDeleteRequestTests/BulkDeleteRequestTests.cs @@ -0,0 +1,167 @@ +using System; +using System.Reflection; +using System.ServiceModel; +using Crm; +using FakeXrmEasy.FakeMessageExecutors; +using Microsoft.Crm.Sdk.Messages; +using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Messages; +using Microsoft.Xrm.Sdk.Query; +using System.Linq; +using Xunit; + +namespace FakeXrmEasy.Tests.FakeContextTests.BulkDeleteRequestTests +{ + public class BulkDeleteRequestTests + { + [Fact] + public void When_can_execute_is_called_with_an_invalid_request_result_is_false() + { + var executor = new BulkDeleteRequestExecutor(); + var anotherRequest = new RetrieveMultipleRequest(); + Assert.False(executor.CanExecute(anotherRequest)); + } + + [Fact] + public void When_execute_is_called_with_a_null_jobname_exception_is_thrown() + { + var context = new XrmFakedContext(); + var executor = new BulkDeleteRequestExecutor(); + BulkDeleteRequest req = new BulkDeleteRequest + { + JobName = null + }; + Assert.Throws>(() => executor.Execute(req, context)); + } + + [Fact] + public void When_execute_is_called_with_a_null_queryset_exception_is_thrown() + { + var context = new XrmFakedContext(); + var executor = new BulkDeleteRequestExecutor(); + BulkDeleteRequest req = new BulkDeleteRequest + { + JobName = "Dummy Job", + QuerySet = null + }; + Assert.Throws>(() => executor.Execute(req, context)); + } + + [Fact] + public void When_execute_is_called_with_a_null_ccrecipients_exception_is_thrown() + { + var context = new XrmFakedContext(); + var executor = new BulkDeleteRequestExecutor(); + BulkDeleteRequest req = new BulkDeleteRequest + { + JobName = "Dummy Job", + QuerySet = new[] + { + new QueryExpression("account"), + }, + CCRecipients = null + }; + Assert.Throws>(() => executor.Execute(req, context)); + } + + [Fact] + public void When_execute_is_called_with_a_null_torecipients_exception_is_thrown() + { + var context = new XrmFakedContext(); + var executor = new BulkDeleteRequestExecutor(); + BulkDeleteRequest req = new BulkDeleteRequest + { + JobName = "Dummy Job", + QuerySet = new[] + { + new QueryExpression("account"), + }, + CCRecipients = new[] + { + Guid.NewGuid(), + Guid.NewGuid() + }, + ToRecipients = null + }; + Assert.Throws>(() => executor.Execute(req, context)); + } + + [Fact] + public void Check_if_contacts_have_been_deleted_after_sending_request() + { + var context = new XrmFakedContext(); + context.ProxyTypesAssembly = Assembly.GetExecutingAssembly(); + var service = context.GetFakedOrganizationService(); + + // initialize data + var parentAccountId = Guid.NewGuid(); + var keepName = "Keep"; + + var contactA = new Contact + { + Id = Guid.NewGuid(), + FirstName = "Delete", + LastName = "Me1", + ParentCustomerId = new EntityReference(Account.EntityLogicalName, parentAccountId) + }; + + var contactB = new Contact + { + Id = Guid.NewGuid(), + FirstName = "Delete", + LastName = "Me2", + ParentCustomerId = new EntityReference(Account.EntityLogicalName, parentAccountId) + }; + + var contactC = new Contact + { + Id = Guid.NewGuid(), + FirstName = keepName, + LastName = "Me", + ParentCustomerId = new EntityReference(Account.EntityLogicalName, Guid.NewGuid()) + }; + + context.Initialize(new[] { contactA, contactB, contactC }); + + var query = new QueryExpression + { + EntityName = Contact.EntityLogicalName, + Distinct = false, + Criteria = new FilterExpression + { + Conditions = + { + new ConditionExpression("parentcustomerid", ConditionOperator.Equal, parentAccountId ) + } + } + }; + + // execute + var request = new BulkDeleteRequest + { + JobName = $"Delete Contacts of Account '{parentAccountId}'", + QuerySet = new QueryExpression[] + { + query + }, + ToRecipients = new[] { Guid.NewGuid() }, + CCRecipients = new Guid[] { }, + SendEmailNotification = false, + RecurrencePattern = string.Empty + }; + + service.Execute(request); + + // validate + var deletedContacts = (from c in context.CreateQuery() + where Equals(c.ParentCustomerId, new EntityReference(Account.EntityLogicalName, parentAccountId)) + select c); + var allContacts = (from c in context.CreateQuery() + select c); + + Assert.Equal(0, deletedContacts.Count()); + Assert.Equal(1, allContacts.Count()); + Assert.Equal(keepName, allContacts.First().FirstName); + } + } +} \ No newline at end of file diff --git a/FakeXrmEasy.Tests.Shared/FakeXrmEasy.Tests.Shared.projitems b/FakeXrmEasy.Tests.Shared/FakeXrmEasy.Tests.Shared.projitems index 5438c461..6b75f5a4 100644 --- a/FakeXrmEasy.Tests.Shared/FakeXrmEasy.Tests.Shared.projitems +++ b/FakeXrmEasy.Tests.Shared/FakeXrmEasy.Tests.Shared.projitems @@ -19,6 +19,7 @@ + From e4b8bc9b04dd1e8da9b140e1256a8d819cd5a575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= Date: Wed, 26 Dec 2018 12:53:18 +0100 Subject: [PATCH 2/2] Add AsyncOperation reflecting the Deletion Status and setting JobId as return parameter. --- .../BulkDeleteRequestExecutor.cs | 26 ++++++++++++++----- .../BulkDeleteRequestTests.cs | 14 ++++++++-- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/FakeXrmEasy.Shared/FakeMessageExecutors/BulkDeleteRequestExecutor.cs b/FakeXrmEasy.Shared/FakeMessageExecutors/BulkDeleteRequestExecutor.cs index a38cf81d..254e1005 100644 --- a/FakeXrmEasy.Shared/FakeMessageExecutors/BulkDeleteRequestExecutor.cs +++ b/FakeXrmEasy.Shared/FakeMessageExecutors/BulkDeleteRequestExecutor.cs @@ -36,6 +36,18 @@ public OrganizationResponse Execute(OrganizationRequest request, XrmFakedContext var service = ctx.GetOrganizationService(); + // generate JobId + var jobId = Guid.NewGuid(); + + // create related asyncOperation + Entity asyncOpertation = new Entity("asyncoperation") + { + Id = jobId + }; + + service.Create(asyncOpertation); + + // delete all records from all queries foreach (QueryExpression queryExpression in bulkDeleteRequest.QuerySet) { EntityCollection recordsToDelete = service.RetrieveMultiple(queryExpression); @@ -44,13 +56,15 @@ public OrganizationResponse Execute(OrganizationRequest request, XrmFakedContext service.Delete(record.LogicalName, record.Id); } } - - return new BulkDeleteResponse() - { - ResponseName = "BulkDeleteResponse" - }; - } + // set ayncoperation to completed + asyncOpertation["statecode"] = new OptionSetValue(3); + service.Update(asyncOpertation); + + // return result + return new BulkDeleteResponse { ResponseName = "BulkDeleteResponse", ["JobId"] = jobId}; + } + public Type GetResponsibleRequestType() { return typeof(BulkDeleteRequest); diff --git a/FakeXrmEasy.Tests.Shared/FakeContextTests/BulkDeleteRequestTests/BulkDeleteRequestTests.cs b/FakeXrmEasy.Tests.Shared/FakeContextTests/BulkDeleteRequestTests/BulkDeleteRequestTests.cs index 3056d900..dbc06789 100644 --- a/FakeXrmEasy.Tests.Shared/FakeContextTests/BulkDeleteRequestTests/BulkDeleteRequestTests.cs +++ b/FakeXrmEasy.Tests.Shared/FakeContextTests/BulkDeleteRequestTests/BulkDeleteRequestTests.cs @@ -140,7 +140,7 @@ public void Check_if_contacts_have_been_deleted_after_sending_request() var request = new BulkDeleteRequest { JobName = $"Delete Contacts of Account '{parentAccountId}'", - QuerySet = new QueryExpression[] + QuerySet = new[] { query }, @@ -150,7 +150,7 @@ public void Check_if_contacts_have_been_deleted_after_sending_request() RecurrencePattern = string.Empty }; - service.Execute(request); + var response = (BulkDeleteResponse)service.Execute(request); // validate var deletedContacts = (from c in context.CreateQuery() @@ -159,9 +159,19 @@ public void Check_if_contacts_have_been_deleted_after_sending_request() var allContacts = (from c in context.CreateQuery() select c); + var asyncOperation = (from a in context.CreateQuery() + where a.AsyncOperationId == response.JobId + select a); + + Assert.NotNull(response); + Assert.IsType(response); + Assert.NotNull(response.JobId); + Assert.NotEqual(Guid.Empty, response.JobId); Assert.Equal(0, deletedContacts.Count()); Assert.Equal(1, allContacts.Count()); Assert.Equal(keepName, allContacts.First().FirstName); + Assert.Equal(1, asyncOperation.Count()); + Assert.Equal(AsyncOperationState.Completed, asyncOperation.First().StateCode); } } } \ No newline at end of file