public async Task CacheReloadServiceReloadIsSuccessfulForCreate() { // arrange var cancellationToken = new CancellationToken(false); var expectedValidCmsApiSharedContentModel = BuildValidCmsApiSharedContentModel(); A.CallTo(() => fakeCmsApiService.GetItemAsync <CmsApiSharedContentModel>(A <string> .Ignored, A <Guid> .Ignored)).Returns(expectedValidCmsApiSharedContentModel); A.CallTo(() => fakeEventMessageService.UpdateAsync(A <CmsApiSharedContentModel> .Ignored)) .Returns(HttpStatusCode.NotFound); A.CallTo(() => fakeEventMessageService.CreateAsync(A <CmsApiSharedContentModel> .Ignored)) .Returns(HttpStatusCode.Created); A.CallTo(() => fakeEventMessageService.DeleteAsync(A <Guid> .Ignored)).Returns(HttpStatusCode.OK); var cacheReloadService = new CacheReloadService(fakeLogger, fakeEventMessageService, fakeCmsApiService, fakeContentTypeMappingService, _config); // act await cacheReloadService.Reload(cancellationToken).ConfigureAwait(false); // assert A.CallTo(() => fakeContentTypeMappingService.AddMapping(A <string> .Ignored, A <Type> .Ignored)) .MustHaveHappenedOnceOrMore(); A.CallTo(() => fakeCmsApiService.GetItemAsync <CmsApiSharedContentModel>(A <string> .Ignored, A <Guid> .Ignored)) .MustHaveHappenedOnceExactly(); A.CallTo(() => fakeEventMessageService.UpdateAsync(A <CmsApiSharedContentModel> .Ignored)) .MustHaveHappenedOnceExactly(); A.CallTo(() => fakeEventMessageService.CreateAsync(A <CmsApiSharedContentModel> .Ignored)) .MustHaveHappenedOnceExactly(); }
public async Task ReloadSharedContent(CancellationToken stoppingToken) { await staticContentDocumentService.PurgeAsync().ConfigureAwait(false); var contentIds = cmsApiClientOptions.ContentIds.Split(",", StringSplitOptions.RemoveEmptyEntries); foreach (var contentId in contentIds) { if (stoppingToken.IsCancellationRequested) { logger.LogWarning("Reload shared-content cache cancelled"); return; } var apiDataModel = await cmsApiService.GetItemAsync <StaticContentItemApiDataModel>("sharedcontent", new Guid(contentId)).ConfigureAwait(false); if (apiDataModel == null) { logger.LogError($"Shared-content: {contentId} not found in API response"); } var staticContentItemModel = mapper.Map <StaticContentItemModel>(apiDataModel); if (!TryValidateModel(staticContentItemModel)) { logger.LogError($"Validation failure for {staticContentItemModel.Title} - {staticContentItemModel.Url}"); return; } await staticContentDocumentService.UpsertAsync(staticContentItemModel).ConfigureAwait(false); } }
public async Task <HttpStatusCode> TransformItemActivity([ActivityTrigger] Uri?url) { _ = url ?? throw new ArgumentNullException(nameof(url)); logger.LogInformation($"Loading Job Group item: {url}"); var lmiSoc = await cmsApiService.GetItemAsync <LmiSoc>(url).ConfigureAwait(false); logger.LogInformation($"Transforming Job Group item for {url} to cache"); var jobGroup = mapper.Map <JobGroupModel>(lmiSoc); if (jobGroup != null) { var existingJobGroup = await jobGroupDocumentService.GetAsync(w => w.Soc == jobGroup.Soc, jobGroup.Soc.ToString(CultureInfo.InvariantCulture)).ConfigureAwait(false); if (existingJobGroup != null) { jobGroup.Etag = existingJobGroup.Etag; } logger.LogInformation($"Upserting Job Groups item: {jobGroup.Soc} / {url}"); return(await jobGroupDocumentService.UpsertAsync(jobGroup).ConfigureAwait(false)); } return(HttpStatusCode.BadRequest); }
public async Task ReloadIsCancelled() { //Arrange var cancellationToken = new CancellationToken(true); var service = new StaticContentReloadService(fakeLogger, fakeMapper, fakeStaticContentDocumentService, fakeCmsApiService, fakeCmsApiClientOptions); //Act await service.Reload(cancellationToken).ConfigureAwait(false); //Assert A.CallTo(() => fakeCmsApiService.GetItemAsync <StaticContentItemApiDataModel>(A <string> .Ignored, A <Guid> .Ignored)).MustNotHaveHappened(); A.CallTo(() => fakeMapper.Map <StaticContentItemModel>(A <StaticContentItemApiDataModel> .Ignored)).MustNotHaveHappened(); A.CallTo(() => fakeStaticContentDocumentService.UpsertAsync(A <StaticContentItemModel> .Ignored)).MustNotHaveHappened(); Assert.True(true); }
private async Task ReloadConfigurationSetTemplate(CancellationToken stoppingToken) { if (stoppingToken.IsCancellationRequested) { logger.LogWarning("Reload configuration set cancelled"); return; } var key = ConfigurationSetKeyHelper.ConfigurationSetKey; var url = new Uri($"{cmsApiClientOptions.BaseAddress}/{Constants.ContentTypeForConfigurationSet}/{key}", UriKind.Absolute); var apiDataModel = await cmsApiService.GetItemAsync <ConfigurationSetApiDataModel>(url).ConfigureAwait(false); if (apiDataModel == null) { logger.LogError($"Configuration set: {key} not found in API response"); return; } if (!apiDataModel.ContentItems.Any()) { logger.LogError($"Configuration set: {key} contains no items"); return; } var configurationSetModel = mapper.Map <ConfigurationSetModel>(apiDataModel); await configurationSetDocumentService.UpsertAsync(configurationSetModel).ConfigureAwait(false); }
public async Task ReloadSharedContent(CancellationToken stoppingToken) { var contentItemKeys = SharedContentKeyHelper.GetSharedContentKeys(); foreach (var key in contentItemKeys) { if (stoppingToken.IsCancellationRequested) { logger.LogWarning("Reload shared content cache cancelled"); return; } var apiDataModel = await cmsApiService.GetItemAsync <SharedContentItemApiDataModel>("sharedcontent", key).ConfigureAwait(false); if (apiDataModel == null) { logger.LogError($"shared content: {key} not found in API response"); } else { var mappedContentItem = mapper.Map <SharedContentItemModel>(apiDataModel); await sharedContentDocumentService.UpsertAsync(mappedContentItem).ConfigureAwait(false); } } }
public async Task <CmsApiSharedContentModel>?GetSharedContentAsync() { logger.LogInformation("Get shared content"); var summaryList = await cmsApiService.GetItemAsync <CmsApiSharedContentModel>("sharedContent", SharedContent).ConfigureAwait(false); logger.LogInformation("Get shared content completed"); return(summaryList); }
public async Task JobGroupCacheRefreshServiceReloadIsSuccessful() { // arrange const HttpStatusCode expectedUpsertResult = HttpStatusCode.OK; A.CallTo(() => fakeCmsApiService.GetItemAsync <CmsApiSharedContentModel>(A <Uri> .Ignored)).Returns(A.Dummy <CmsApiSharedContentModel>()); A.CallTo(() => fakeMapper.Map <ContentItemModel>(A <CmsApiSharedContentModel> .Ignored)).Returns(A.Dummy <ContentItemModel>()); A.CallTo(() => fakeContentItemDocumentService.UpsertAsync(A <ContentItemModel> .Ignored)).Returns(expectedUpsertResult); // act await sharedContentCacheReloadService.ReloadAsync(new CancellationToken(false)).ConfigureAwait(false); // assert A.CallTo(() => fakeContentTypeMappingService.AddMapping(A <string> .Ignored, A <Type> .Ignored)).MustHaveHappenedOnceExactly(); A.CallTo(() => fakeCmsApiService.GetItemAsync <CmsApiSharedContentModel>(A <Uri> .Ignored)).MustHaveHappenedOnceExactly(); A.CallTo(() => fakeMapper.Map <ContentItemModel>(A <CmsApiSharedContentModel> .Ignored)).MustHaveHappenedOnceExactly(); A.CallTo(() => fakeContentItemDocumentService.UpsertAsync(A <ContentItemModel> .Ignored)).MustHaveHappenedOnceExactly(); }
public async Task LmiOrchestrationTriggerTransformItemAsyncIsSuccessful() { // Arrange const HttpStatusCode expectedResult = HttpStatusCode.OK; var dummyLmiSoc = A.Dummy <LmiSoc>(); var dummyJobgroup = A.Dummy <JobGroupModel>(); A.CallTo(() => fakeCmsApiService.GetItemAsync <LmiSoc>(A <Uri> .Ignored)).Returns(dummyLmiSoc); A.CallTo(() => fakeMapper.Map <JobGroupModel>(A <LmiSoc> .Ignored)).Returns(dummyJobgroup); A.CallTo(() => fakeJobGroupDocumentService.GetAsync(A <Expression <Func <JobGroupModel, bool> > > .Ignored, A <string> .Ignored)).Returns(dummyJobgroup); A.CallTo(() => fakeJobGroupDocumentService.UpsertAsync(A <JobGroupModel> .Ignored)).Returns(expectedResult); // Act var result = await lmiOrchestrationTrigger.TransformItemActivity(new Uri("https://somewhere.com", UriKind.Absolute)).ConfigureAwait(false); // Assert A.CallTo(() => fakeCmsApiService.GetItemAsync <LmiSoc>(A <Uri> .Ignored)).MustHaveHappenedOnceExactly(); A.CallTo(() => fakeMapper.Map <JobGroupModel>(A <LmiSoc> .Ignored)).MustHaveHappenedOnceExactly(); A.CallTo(() => fakeJobGroupDocumentService.GetAsync(A <Expression <Func <JobGroupModel, bool> > > .Ignored, A <string> .Ignored)).MustHaveHappenedOnceExactly(); A.CallTo(() => fakeJobGroupDocumentService.UpsertAsync(A <JobGroupModel> .Ignored)).MustHaveHappenedOnceExactly(); Assert.Equal(expectedResult, result); }
public async Task SharedContentCacheReloadServiceReloadAllCancellationRequestedCancels() { //Arrange var cancellationToken = new CancellationToken(true); var sharedContentCacheReloadService = new SharedContentCacheReloadService(A.Fake <ILogger <SharedContentCacheReloadService> >(), fakeMapper, fakeSharedContentItemDocumentService, fakeCmsApiService); //Act await sharedContentCacheReloadService.Reload(cancellationToken).ConfigureAwait(false); //Assert A.CallTo(() => fakeCmsApiService.GetItemAsync <SharedContentItemApiDataModel>(A <string> .Ignored, A <Guid> .Ignored)).MustNotHaveHappened(); A.CallTo(() => fakeSharedContentItemDocumentService.UpsertAsync(A <SharedContentItemModel> .Ignored)).MustNotHaveHappened(); }
public async Task ConfigurationSetReloadServiceReloadCancellationRequestedCancels() { //Arrange var dummyCmsApiClientOptions = A.Dummy <CmsApiClientOptions>(); var cancellationToken = new CancellationToken(true); var configurationSetReloadService = new ConfigurationSetReloadService(A.Fake <ILogger <ConfigurationSetReloadService> >(), fakeMapper, fakeConfigurationSetDocumentService, fakeCmsApiService, dummyCmsApiClientOptions, fakeContentTypeMappingService); //Act await configurationSetReloadService.Reload(cancellationToken).ConfigureAwait(false); //Assert A.CallTo(() => fakeCmsApiService.GetItemAsync <ConfigurationSetApiDataModel>(A <Uri> .Ignored)).MustNotHaveHappened(); A.CallTo(() => fakeMapper.Map <ConfigurationSetModel>(A <ConfigurationSetApiDataModel> .Ignored)).MustNotHaveHappened(); A.CallTo(() => fakeConfigurationSetDocumentService.UpsertAsync(A <ConfigurationSetModel> .Ignored)).MustNotHaveHappened(); }
public async Task <HttpStatusCode> ProcessSharedContentAsync(Guid eventId, Uri?url) { var apiDataModel = await cmsApiService.GetItemAsync <CmsApiSharedContentModel>(url).ConfigureAwait(false); var contentItemModel = mapper.Map <ContentItemModel>(apiDataModel); if (contentItemModel == null) { logger.LogWarning($"Event Id: {eventId} - no shared content for: {url}"); return(HttpStatusCode.NoContent); } var contentResult = await contentItemDocumentService.UpsertAsync(contentItemModel).ConfigureAwait(false); logger.LogInformation($"Event Id: {eventId} - processed shared content result: {contentResult} - for: {url}"); return(contentResult); }
public async Task <HttpStatusCode> ProcessContentAsync(Uri url, Guid contentId) { if (url == null) { throw new ArgumentNullException(nameof(url)); } url = Combine(url.ToString(), "true?checkAncestryById=true"); // This enables the multiDirectional support needed for page locations var apiDataModel = await cmsApiService.GetItemAsync <CmsApiDataModel>(url).ConfigureAwait(false); var contentPageModel = mapper.Map <ContentPageModel>(apiDataModel); if (contentPageModel == null) { return(HttpStatusCode.NoContent); } if (!TryValidateModel(contentPageModel)) { return(HttpStatusCode.BadRequest); } var existingContentPageModel = await contentPageService.GetByIdAsync(contentId).ConfigureAwait(false); var contentResult = await eventMessageService.UpdateAsync(contentPageModel).ConfigureAwait(false); if (contentResult == HttpStatusCode.NotFound) { contentResult = await eventMessageService.CreateAsync(contentPageModel).ConfigureAwait(false); } if (contentResult == HttpStatusCode.OK || contentResult == HttpStatusCode.Created) { await eventGridService.CompareAndSendEventAsync(existingContentPageModel, contentPageModel).ConfigureAwait(false); var contentItemIds = contentPageModel.AllContentItemIds; contentItemIds.AddRange(contentPageModel.AllPageLocationIds); contentCacheService.AddOrReplace(contentId, contentItemIds); } return(contentResult); }
public async Task <HttpStatusCode> ProcessContentAsync(Uri url, Guid contentId) { var apiDataModel = await cmsApiService.GetItemAsync <CmsApiSharedContentModel>(url).ConfigureAwait(false); if (apiDataModel == null) { return(HttpStatusCode.NoContent); } apiDataModel.Id = apiDataModel.ItemId.Value; var contentResult = await eventMessageService.UpdateAsync(apiDataModel).ConfigureAwait(false); if (contentResult == HttpStatusCode.NotFound) { contentResult = await eventMessageService.CreateAsync(apiDataModel).ConfigureAwait(false); } return(contentResult); }
public async Task <HttpStatusCode> ProcessContentItemAsync(Uri url) { var apiDataModel = await cmsApiService.GetItemAsync <StaticContentItemApiDataModel>(url).ConfigureAwait(false); var staticContentItemModel = mapper.Map <StaticContentItemModel>(apiDataModel); if (staticContentItemModel == null) { return(HttpStatusCode.NoContent); } if (!TryValidateModel(staticContentItemModel)) { return(HttpStatusCode.BadRequest); } var contentResult = await configurationSetDocumentService.UpsertAsync(staticContentItemModel).ConfigureAwait(false); return(contentResult); }
private async Task ReloadCacheItem(Guid itemId, CancellationToken stoppingToken) { if (stoppingToken.IsCancellationRequested) { logger.LogWarning("Reload shared content cancelled"); return; } var url = new Uri($"{cmsApiClientOptions.BaseAddress}/{Constants.ContentTypeSharedContent.ToLowerInvariant()}/{itemId}", UriKind.Absolute); var apiDataModel = await cmsApiService.GetItemAsync <CmsApiSharedContentModel>(url).ConfigureAwait(false); if (apiDataModel == null) { logger.LogError($"Shared content: {itemId} not found in API response"); return; } var contentItemModel = mapper.Map <ContentItemModel>(apiDataModel); await contentItemDocumentService.UpsertAsync(contentItemModel).ConfigureAwait(false); }
public async Task <HttpStatusCode> ProcessContentAsync(Uri url, Guid contentId) { var apiDataModel = await cmsApiService.GetItemAsync <CmsApiDataModel>(url).ConfigureAwait(false); var contentPageModel = mapper.Map <ContentPageModel>(apiDataModel); if (contentPageModel == null) { return(HttpStatusCode.NoContent); } if (!TryValidateModel(contentPageModel)) { return(HttpStatusCode.BadRequest); } var existingContentPageModel = await contentPageService.GetByIdAsync(contentId).ConfigureAwait(false); var contentResult = await eventMessageService.UpdateAsync(contentPageModel).ConfigureAwait(false); if (contentResult == HttpStatusCode.NotFound) { contentResult = await eventMessageService.CreateAsync(contentPageModel).ConfigureAwait(false); } if (contentResult == HttpStatusCode.OK || contentResult == HttpStatusCode.Created) { await eventGridService.CompareAndSendEventAsync(existingContentPageModel, contentPageModel).ConfigureAwait(false); var contentItemIds = contentPageModel.AllContentItemIds; contentItemIds.AddRange(contentPageModel.AllPageLocationIds); contentCacheService.AddOrReplace(contentId, contentItemIds); } return(contentResult); }
public async Task GetAndSaveItemAsync(CmsApiSummaryItemModel item, CancellationToken stoppingToken) { _ = item ?? throw new ArgumentNullException(nameof(item)); var url = Combine(item.Url !.ToString(), "true?checkAncestryById=true"); // This enables the multiDirectional support needed for page locations try { logger.LogInformation($"Get details for {item.Title} - {url}"); var apiDataModel = await cmsApiService.GetItemAsync <CmsApiDataModel>(url).ConfigureAwait(false); if (apiDataModel == null) { logger.LogWarning($"No details returned from {item.Title} - {url}"); return; } if (stoppingToken.IsCancellationRequested) { logger.LogWarning("Process item get and save cancelled"); return; } var contentPageModel = mapper.Map <ContentPageModel>(apiDataModel); if (!TryValidateModel(contentPageModel)) { logger.LogError($"Validation failure for {item.Title} - {url}"); return; } logger.LogInformation($"Updating cache with {item.Title} - {url}"); var result = await eventMessageService.UpdateAsync(contentPageModel).ConfigureAwait(false); if (result == HttpStatusCode.NotFound) { logger.LogInformation($"Does not exist, creating cache with {item.Title} - {url}"); result = await eventMessageService.CreateAsync(contentPageModel).ConfigureAwait(false); if (result == HttpStatusCode.Created) { logger.LogInformation($"Created cache with {item.Title} - {url}"); } else { logger.LogError($"Cache create error status {result} from {item.Title} - {url}"); } } else { logger.LogInformation($"Updated cache with {item.Title} - {url}"); } var contentItemIds = contentPageModel.AllContentItemIds; contentItemIds.AddRange(contentPageModel.AllPageLocationIds); contentCacheService.AddOrReplace(contentPageModel.Id, contentItemIds); } catch (Exception ex) { logger.LogError(ex, $"Error in get and save for {item.Title} - {url}"); } }
public async Task ProcessMessageAsyncDeleteReturnsSuccess() { //Arrange const HttpStatusCode expectedResult = HttpStatusCode.OK; var service = new WebhooksService(fakeLogger, fakeMapper, fakeCmsApiService, fakeConfigurationSetDocumentService); var dummyStaticContentItemApiDataModel = A.Dummy <StaticContentItemApiDataModel>(); var validStaticContentItemModel = BuildValidStaticContentItemModel(); A.CallTo(() => fakeConfigurationSetDocumentService.DeleteAsync(A <Guid> .Ignored)).Returns(true); //Act var result = await service.ProcessMessageAsync(WebhookCacheOperation.Delete, Guid.NewGuid(), Guid.NewGuid(), "https://somewhere.com").ConfigureAwait(false); //Assert A.CallTo(() => fakeCmsApiService.GetItemAsync <StaticContentItemApiDataModel>(A <Uri> .Ignored)).MustNotHaveHappened(); A.CallTo(() => fakeMapper.Map <StaticContentItemModel>(A <StaticContentItemApiDataModel> .Ignored)).MustNotHaveHappened(); A.CallTo(() => fakeConfigurationSetDocumentService.UpsertAsync(A <StaticContentItemModel> .Ignored)).MustNotHaveHappened(); A.CallTo(() => fakeConfigurationSetDocumentService.DeleteAsync(A <Guid> .Ignored)).MustHaveHappenedOnceExactly(); Assert.Equal(expectedResult, result); }
public async Task WebhooksContentServiceProcessContentForSharedContentItemReturnsSuccess() { // Arrange const HttpStatusCode expectedResult = HttpStatusCode.OK; A.CallTo(() => fakeCmsApiService.GetItemAsync <CmsApiSharedContentModel>(A <Uri> .Ignored)).Returns(A.Dummy <CmsApiSharedContentModel>()); A.CallTo(() => fakeMapper.Map <ContentItemModel>(A <CmsApiSharedContentModel> .Ignored)).Returns(A.Dummy <ContentItemModel>()); A.CallTo(() => fakeContentItemDocumentService.UpsertAsync(A <ContentItemModel> .Ignored)).Returns(expectedResult); // Act var result = await webhooksContentService.ProcessContentAsync(false, Guid.NewGuid(), null, "https://somewhere.com", MessageContentType.SharedContentItem).ConfigureAwait(false); // Assert A.CallTo(() => fakeJobGroupCacheRefreshService.ReloadAsync(A <Uri> .Ignored)).MustNotHaveHappened(); A.CallTo(() => fakeJobGroupCacheRefreshService.ReloadItemAsync(A <Uri> .Ignored)).MustNotHaveHappened(); A.CallTo(() => fakeCmsApiService.GetItemAsync <CmsApiSharedContentModel>(A <Uri> .Ignored)).MustHaveHappenedOnceExactly(); A.CallTo(() => fakeMapper.Map <ContentItemModel>(A <CmsApiSharedContentModel> .Ignored)).MustHaveHappenedOnceExactly(); A.CallTo(() => fakeContentItemDocumentService.UpsertAsync(A <ContentItemModel> .Ignored)).MustHaveHappenedOnceExactly(); A.CallTo(() => fakeJobGroupPublishedRefreshService.ReloadAsync(A <Uri> .Ignored)).MustNotHaveHappened(); A.CallTo(() => fakeJobGroupPublishedRefreshService.ReloadItemAsync(A <Uri> .Ignored)).MustNotHaveHappened(); A.CallTo(() => fakeEventGridService.SendEventAsync(A <EventGridEventData> .Ignored, A <string> .Ignored, A <string> .Ignored)).MustNotHaveHappened(); Assert.Equal(expectedResult, result); }
public async Task CacheReloadServiceReloadIsSuccessfulForCreate() { // arrange const int NumerOfSummaryItems = 2; const int NumberOfDeletions = 3; var cancellationToken = new CancellationToken(false); var expectedValidContentPageModel = BuildValidContentPageModel(); var fakePagesSummaryItemModels = BuldFakePagesSummaryItemModel(NumerOfSummaryItems); var fakeCachedContentPageModels = BuldFakeContentPageModels(NumberOfDeletions); A.CallTo(() => fakeCmsApiService.GetSummaryAsync <CmsApiSummaryItemModel>()).Returns(fakePagesSummaryItemModels); A.CallTo(() => fakeCmsApiService.GetItemAsync <CmsApiDataModel>(A <Uri> .Ignored)).Returns(A.Fake <CmsApiDataModel>()); A.CallTo(() => fakeMapper.Map <ContentPageModel>(A <CmsApiDataModel> .Ignored)).Returns(expectedValidContentPageModel); A.CallTo(() => fakeEventMessageService.UpdateAsync(A <ContentPageModel> .Ignored)).Returns(HttpStatusCode.NotFound); A.CallTo(() => fakeEventMessageService.CreateAsync(A <ContentPageModel> .Ignored)).Returns(HttpStatusCode.Created); A.CallTo(() => fakeEventMessageService.GetAllCachedItemsAsync()).Returns(fakeCachedContentPageModels); A.CallTo(() => fakeEventMessageService.DeleteAsync(A <Guid> .Ignored)).Returns(HttpStatusCode.OK); A.CallTo(() => fakeContentCacheService.AddOrReplace(A <Guid> .Ignored, A <List <Guid> > .Ignored, A <string> .Ignored)); var cacheReloadService = new CacheReloadService(fakeLogger, fakeMapper, fakeEventMessageService, fakeCmsApiService, fakeContentCacheService, fakeAppRegistryService, fakeContentTypeMappingService, fakeApiCacheService); // act await cacheReloadService.Reload(cancellationToken).ConfigureAwait(false); // assert A.CallTo(() => fakeContentTypeMappingService.AddMapping(A <string> .Ignored, A <Type> .Ignored)).MustHaveHappenedOnceOrMore(); A.CallTo(() => fakeCmsApiService.GetSummaryAsync <CmsApiSummaryItemModel>()).MustHaveHappenedOnceExactly(); A.CallTo(() => fakeContentCacheService.Clear()).MustHaveHappenedOnceExactly(); A.CallTo(() => fakeCmsApiService.GetItemAsync <CmsApiDataModel>(A <Uri> .Ignored)).MustHaveHappened(NumerOfSummaryItems, Times.Exactly); A.CallTo(() => fakeMapper.Map <ContentPageModel>(A <CmsApiDataModel> .Ignored)).MustHaveHappened(NumerOfSummaryItems, Times.Exactly); A.CallTo(() => fakeEventMessageService.UpdateAsync(A <ContentPageModel> .Ignored)).MustHaveHappened(NumerOfSummaryItems, Times.Exactly); A.CallTo(() => fakeEventMessageService.CreateAsync(A <ContentPageModel> .Ignored)).MustHaveHappened(NumerOfSummaryItems, Times.Exactly); A.CallTo(() => fakeEventMessageService.GetAllCachedItemsAsync()).MustHaveHappenedTwiceExactly(); A.CallTo(() => fakeEventMessageService.DeleteAsync(A <Guid> .Ignored)).MustHaveHappened(NumberOfDeletions, Times.Exactly); A.CallTo(() => fakeContentCacheService.AddOrReplace(A <Guid> .Ignored, A <List <Guid> > .Ignored, A <string> .Ignored)).MustHaveHappened(NumerOfSummaryItems, Times.Exactly); A.CallTo(() => fakeAppRegistryService.PagesDataLoadAsync()).MustHaveHappenedOnceExactly(); }