public async Task DropsMessageAfterMissingPackageRetryCountIsReached() { var validationTrackingId = Guid.NewGuid(); var messageData = PackageValidationMessageData.NewProcessValidationSet( "packageId", "1.2.3", validationTrackingId, ValidatingType.SymbolPackage, entityKey: null); CoreSymbolPackageServiceMock .Setup(ps => ps.FindPackageByIdAndVersionStrict("packageId", "1.2.3")) .Returns <SymbolPackage>(null) .Verifiable(); TelemetryServiceMock .Setup(t => t.TrackMissingPackageForValidationMessage("packageId", "1.2.3", validationTrackingId.ToString())) .Verifiable(); var handler = CreateHandler(); Assert.False(await handler.HandleAsync(OverrideDeliveryCount(messageData, deliveryCount: 1))); Assert.False(await handler.HandleAsync(OverrideDeliveryCount(messageData, deliveryCount: 2))); Assert.True(await handler.HandleAsync(OverrideDeliveryCount(messageData, deliveryCount: 3))); CoreSymbolPackageServiceMock.Verify(ps => ps.FindPackageByIdAndVersionStrict("packageId", "1.2.3"), Times.Exactly(3)); TelemetryServiceMock.Verify(t => t.TrackMissingPackageForValidationMessage("packageId", "1.2.3", validationTrackingId.ToString()), Times.Once); }
public async Task MarksPackageStatusBasedOnValidatorResults( ValidationStatus validation, PackageStatus fromStatus, PackageStatus toStatus, bool expectedSetPackageStatusCall) { AddValidation("validation1", validation); Package.PackageStatusKey = fromStatus; TimeSpan duration = default(TimeSpan); TelemetryServiceMock .Setup(ts => ts.TrackTotalValidationDuration(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Guid>(), It.IsAny <TimeSpan>(), It.IsAny <bool>())) .Callback <string, string, Guid, TimeSpan, bool>((_1, _2, _3, t, _4) => duration = t); ProcessorStats.AnyRequiredValidationSucceeded = true; ProcessorStats.AnyValidationSucceeded = true; var processor = CreateProcessor(); var before = DateTime.UtcNow; await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); var after = DateTime.UtcNow; if (expectedSetPackageStatusCall) { PackageStateProcessorMock.Verify( x => x.SetStatusAsync(PackageValidatingEntity, ValidationSet, toStatus), Times.Once); PackageStateProcessorMock.Verify( x => x.SetStatusAsync(It.IsAny <PackageValidatingEntity>(), It.IsAny <PackageValidationSet>(), It.IsAny <PackageStatus>()), Times.Once); } else { PackageStateProcessorMock.Verify( x => x.SetStatusAsync(It.IsAny <PackageValidatingEntity>(), It.IsAny <PackageValidationSet>(), It.IsAny <PackageStatus>()), Times.Never); } if (validation != ValidationStatus.Failed) { PackageFileServiceMock.Verify( x => x.DeletePackageForValidationSetAsync(ValidationSet), Times.Never); } else { PackageFileServiceMock.Verify( x => x.DeletePackageForValidationSetAsync(ValidationSet), Times.Once); } TelemetryServiceMock .Verify(ts => ts.TrackTotalValidationDuration(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Guid>(), It.IsAny <TimeSpan>(), It.IsAny <bool>()), Times.Once()); Assert.InRange(duration, before - ValidationSet.Created, after - ValidationSet.Created); Assert.Equal(ValidationSetStatus.Completed, ValidationSet.ValidationSetStatus); }
public async Task SetsPackageStreamMetadataIfChanged() { var content = "Hello, world."; var expectedHash = "rQw3wx1psxXzqB8TyM3nAQlK2RcluhsNwxmcqXE2YbgoDW735o8TPmIR4uWpoxUERddvFwjgRSGw7gNPCwuvJg=="; var stream = new MemoryStream(Encoding.ASCII.GetBytes(content)); PackageStreamMetadata actual = null; PackageFileServiceMock .Setup(x => x.DownloadPackageFileToDiskAsync(Package)) .ReturnsAsync(stream); PackageServiceMock .Setup(x => x.UpdatePackageStreamMetadataAsync(Package, It.IsAny <PackageStreamMetadata>(), false)) .Returns(Task.CompletedTask) .Callback <Package, PackageStreamMetadata, bool>((_, m, __) => actual = m); await Target.SetPackageStatusAsync(Package, ValidationSet, PackageStatus.Available); Assert.NotNull(actual); Assert.Equal(content.Length, actual.Size); Assert.Equal(expectedHash, actual.Hash); Assert.Equal("SHA512", actual.HashAlgorithm); PackageServiceMock.Verify( x => x.UpdatePackageStreamMetadataAsync(Package, actual, false), Times.Once); TelemetryServiceMock.Verify( x => x.TrackDurationToHashPackage( It.Is <TimeSpan>(y => y > TimeSpan.Zero), Package.PackageRegistration.Id, Package.NormalizedVersion, "SHA512", "System.IO.MemoryStream"), Times.Once); }
public async Task TriesToGetValidationSetFirst() { ValidationStorageMock .Setup(vs => vs.GetValidationSetAsync(ValidationSet.ValidationTrackingId)) .ReturnsAsync(ValidationSet) .Verifiable(); var provider = CreateProvider(); var set = await provider.TryGetOrCreateValidationSetAsync(PackageValidationMessageData, PackageValidatingEntity); ValidationStorageMock .Verify(vs => vs.GetValidationSetAsync(ValidationSet.ValidationTrackingId), Times.Once()); Assert.Same(ValidationSet, set); PackageFileServiceMock.Verify( x => x.CopyPackageFileForValidationSetAsync(It.IsAny <PackageValidationSet>()), Times.Never); PackageFileServiceMock.Verify( x => x.CopyValidationPackageForValidationSetAsync(It.IsAny <PackageValidationSet>()), Times.Never); PackageFileServiceMock.Verify( x => x.BackupPackageFileFromValidationSetPackageAsync(It.IsAny <PackageValidationSet>()), Times.Never); TelemetryServiceMock.Verify( x => x.TrackDurationToValidationSetCreation(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Guid>(), It.IsAny <TimeSpan>()), Times.Never); }
public async Task DoesNotReEnqueueProcessingIfValidationSetTimesOut() { const int postponeMinutes = 1; AddValidation("validation1", ValidationStatus.Incomplete); Configuration.TimeoutValidationSetAfter = TimeSpan.FromDays(1); Configuration.ValidationMessageRecheckPeriod = TimeSpan.FromMinutes(postponeMinutes); ValidationSet.Created = DateTime.UtcNow - TimeSpan.FromDays(1) - TimeSpan.FromHours(1); ValidationStorageServiceMock .Setup(s => s.UpdateValidationSetAsync(It.IsAny <PackageValidationSet>())) .Callback <PackageValidationSet>(s => s.Updated = DateTime.UtcNow) .Returns(Task.FromResult(0)); var processor = CreateProcessor(); await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); TelemetryServiceMock .Verify(t => t.TrackValidationSetTimeout(Package.PackageRegistration.Id, Package.NormalizedVersion, ValidationSet.ValidationTrackingId)); ValidationEnqueuerMock .Verify(ve => ve.StartValidationAsync(It.IsAny <PackageValidationMessageData>(), It.IsAny <DateTimeOffset>()), Times.Never); PackageFileServiceMock .Verify(x => x.DeletePackageForValidationSetAsync(It.IsAny <PackageValidationSet>()), Times.Never); }
public async Task DoesNotEmitTelemetryIfMultipleValidationSetsExist() { const string validation1 = "validation1"; Configuration.Validations = new List <ValidationConfigurationItem> { new ValidationConfigurationItem() { Name = validation1, TrackAfter = TimeSpan.FromDays(1), RequiredValidations = new List <string> { } } }; Guid validationTrackingId = Guid.NewGuid(); ValidationStorageMock .Setup(vs => vs.GetValidationSetAsync(validationTrackingId)) .ReturnsAsync((PackageValidationSet)null) .Verifiable(); PackageValidationSet createdSet = null; ValidationStorageMock .Setup(vs => vs.CreateValidationSetAsync(It.IsAny <PackageValidationSet>())) .Returns <PackageValidationSet>(pvs => Task.FromResult(pvs)) .Callback <PackageValidationSet>(pvs => createdSet = pvs) .Verifiable(); ValidationStorageMock .Setup(vs => vs.GetValidationSetCountAsync(It.IsAny <IValidatingEntity <Package> >())) .ReturnsAsync(2); ValidationStorageMock .Setup(vs => vs.OtherRecentValidationSetForPackageExists(It.IsAny <IValidatingEntity <Package> >(), It.IsAny <TimeSpan>(), It.IsAny <Guid>())) .ReturnsAsync(false); var provider = new ValidationSetProvider <Package>( ValidationStorageMock.Object, PackageFileServiceMock.Object, ValidatorProvider.Object, ConfigurationAccessorMock.Object, TelemetryServiceMock.Object, LoggerMock.Object); var packageValidationMessageData = new ProcessValidationSetData( Package.PackageRegistration.Id, Package.NormalizedVersion, validationTrackingId, ValidatingType.Package, Package.Key); var returnedSet = await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, PackageValidatingEntity); ValidationStorageMock .Verify(vs => vs.CreateValidationSetAsync(It.IsAny <PackageValidationSet>()), Times.Once); TelemetryServiceMock.Verify( x => x.TrackDurationToValidationSetCreation(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Guid>(), It.IsAny <TimeSpan>()), Times.Never); }
public async Task TracksTimedOutValidators() { const int postponeMinutes = 1; AddValidation( "IncompleteAndNotTimedOut", ValidationStatus.Incomplete, validationStart: DateTime.UtcNow, trackAfter: TimeSpan.FromDays(1)); AddValidation( "IncompleteButTimedOut", ValidationStatus.Incomplete, validationStart: DateTime.UtcNow + TimeSpan.FromDays(-5), trackAfter: TimeSpan.FromDays(1)); Configuration.TimeoutValidationSetAfter = TimeSpan.FromDays(1); Configuration.ValidationMessageRecheckPeriod = TimeSpan.FromMinutes(postponeMinutes); var processor = CreateProcessor(); await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); TelemetryServiceMock .Verify(t => t.TrackValidatorTimeout("IncompleteButTimedOut")); ValidationEnqueuerMock .Verify(ve => ve.StartValidationAsync(It.IsAny <PackageValidationMessageData>(), It.IsAny <DateTimeOffset>()), Times.Once); PackageFileServiceMock .Verify(x => x.DeletePackageForValidationSetAsync(It.IsAny <PackageValidationSet>()), Times.Never); }
public async Task DoesNotSendValidatingTooLongMessageOnRevalidations() { const int postponeMinutes = 1; AddValidation("validation1", ValidationStatus.Incomplete); Configuration.TimeoutValidationSetAfter = TimeSpan.FromDays(1); Configuration.ValidationSetNotificationTimeout = TimeSpan.FromMinutes(20); Configuration.ValidationMessageRecheckPeriod = TimeSpan.FromMinutes(postponeMinutes); ValidationSet.Created = DateTime.UtcNow - TimeSpan.FromMinutes(21); ValidationSet.Updated = DateTime.UtcNow - TimeSpan.FromMinutes(15); ValidationStorageServiceMock .Setup(s => s.UpdateValidationSetAsync(It.IsAny <PackageValidationSet>())) .Callback <PackageValidationSet>(s => s.Updated = DateTime.UtcNow) .Returns(Task.FromResult(0)); ValidationStorageServiceMock .Setup(s => s.GetValidationSetCountAsync(PackageValidatingEntity)) .Returns(Task.FromResult(2)); // Process the outcome once - the "too long to validate" message should NOT be sent. var processor = CreateProcessor(); await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); TelemetryServiceMock .Verify(t => t.TrackSentValidationTakingTooLongMessage(Package.PackageRegistration.Id, Package.NormalizedVersion, ValidationSet.ValidationTrackingId), Times.Never); MessageServiceMock .Verify(m => m.SendValidationTakingTooLongMessageAsync(Package), Times.Never); ValidationEnqueuerMock .Verify(ve => ve.StartValidationAsync(It.IsAny <PackageValidationMessageData>(), It.IsAny <DateTimeOffset>()), Times.Once); PackageFileServiceMock .Verify(x => x.DeletePackageForValidationSetAsync(It.IsAny <PackageValidationSet>()), Times.Never); }
private List <string> RecordOperationOrder() { var operations = new List <string>(); PackageStateProcessorMock .Setup(x => x.SetStatusAsync(It.IsAny <IValidatingEntity <Package> >(), It.IsAny <PackageValidationSet>(), It.IsAny <PackageStatus>())) .Returns(Task.CompletedTask) .Callback(() => operations.Add(nameof(IStatusProcessor <Package> .SetStatusAsync))); ValidationStorageServiceMock .Setup(x => x.UpdateValidationSetAsync(It.IsAny <PackageValidationSet>())) .Returns(Task.CompletedTask) .Callback(() => operations.Add(nameof(IValidationStorageService.UpdateValidationSetAsync))); MessageServiceMock .Setup(x => x.SendPublishedMessageAsync(It.IsAny <Package>())) .Returns(Task.CompletedTask) .Callback(() => operations.Add(nameof(IMessageService <Package> .SendPublishedMessageAsync))); MessageServiceMock .Setup(x => x.SendValidationFailedMessageAsync(It.IsAny <Package>(), It.IsAny <PackageValidationSet>())) .Returns(Task.CompletedTask) .Callback(() => operations.Add(nameof(IMessageService <Package> .SendValidationFailedMessageAsync))); TelemetryServiceMock .Setup(x => x.TrackTotalValidationDuration(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Guid>(), It.IsAny <TimeSpan>(), It.IsAny <bool>())) .Callback(() => operations.Add(nameof(ITelemetryService.TrackTotalValidationDuration))); PackageFileServiceMock .Setup(x => x.DeletePackageForValidationSetAsync(It.IsAny <PackageValidationSet>())) .Returns(Task.CompletedTask) .Callback(() => operations.Add(nameof(IValidationFileService.DeletePackageForValidationSetAsync))); return(operations); }
public async Task SetsPackageStatusToFailedValidation() { await Target.SetPackageStatusAsync(Package, ValidationSet, PackageStatus.FailedValidation); PackageServiceMock.Verify( x => x.UpdatePackageStatusAsync(Package, PackageStatus.FailedValidation, true), Times.Once); PackageServiceMock.Verify( x => x.UpdatePackageStatusAsync(It.IsAny <Package>(), It.IsAny <PackageStatus>(), It.IsAny <bool>()), Times.Once); TelemetryServiceMock.Verify( x => x.TrackPackageStatusChange(PackageStatus.Validating, PackageStatus.FailedValidation), Times.Once); PackageFileServiceMock.Verify( x => x.DeletePackageForValidationSetAsync(ValidationSet), Times.Never); }
public async Task MarksPackageStatusBasedOnValidatorResults( ValidationStatus validation, PackageStatus fromStatus, PackageStatus toStatus, bool setPackageStatus) { AddValidation("validation1", validation); Package.PackageStatusKey = fromStatus; TimeSpan duration = default(TimeSpan); TelemetryServiceMock .Setup(ts => ts.TrackTotalValidationDuration(It.IsAny <TimeSpan>(), It.IsAny <bool>())) .Callback <TimeSpan, bool>((t, _) => duration = t); var processor = CreateProcessor(); var before = DateTime.UtcNow; await processor.ProcessValidationOutcomeAsync(ValidationSet, Package); var after = DateTime.UtcNow; if (setPackageStatus) { PackageStateProcessorMock.Verify( x => x.SetPackageStatusAsync(Package, ValidationSet, toStatus), Times.Once); PackageStateProcessorMock.Verify( x => x.SetPackageStatusAsync(It.IsAny <Package>(), It.IsAny <PackageValidationSet>(), It.IsAny <PackageStatus>()), Times.Once); } else { PackageStateProcessorMock.Verify( x => x.SetPackageStatusAsync(It.IsAny <Package>(), It.IsAny <PackageValidationSet>(), It.IsAny <PackageStatus>()), Times.Never); } PackageFileServiceMock.Verify( x => x.DeletePackageForValidationSetAsync(ValidationSet), Times.Once); TelemetryServiceMock .Verify(ts => ts.TrackTotalValidationDuration(It.IsAny <TimeSpan>(), It.IsAny <bool>()), Times.Once()); Assert.InRange(duration, before - ValidationSet.Created, after - ValidationSet.Created); }
public async Task TracksMissingNupkgForAvailablePackage(bool validationFileExists) { Package.PackageStatusKey = PackageStatus.Available; PackageFileServiceMock .Setup(pfs => pfs.DoesPackageFileExistAsync(Package)) .ReturnsAsync(false); PackageFileServiceMock .Setup(pfs => pfs.DoesValidationPackageFileExistAsync(Package)) .ReturnsAsync(validationFileExists); await Target.SetPackageStatusAsync(Package, ValidationSet, PackageStatus.Available); TelemetryServiceMock.Verify( x => x.TrackMissingNupkgForAvailablePackage( ValidationSet.PackageId, ValidationSet.PackageNormalizedVersion, ValidationSet.ValidationTrackingId.ToString()), Times.Once); }
public async Task EmitsTelemetryOnStatusChange(PackageStatus fromStatus, PackageStatus toStatus) { Package.PackageStatusKey = fromStatus; await Target.SetPackageStatusAsync(Package, ValidationSet, toStatus); if (fromStatus != toStatus) { TelemetryServiceMock.Verify( x => x.TrackPackageStatusChange(fromStatus, toStatus), Times.Once); TelemetryServiceMock.Verify( x => x.TrackPackageStatusChange(It.IsAny <PackageStatus>(), It.IsAny <PackageStatus>()), Times.Once); } else { TelemetryServiceMock.Verify( x => x.TrackPackageStatusChange(It.IsAny <PackageStatus>(), It.IsAny <PackageStatus>()), Times.Never); } }
public async Task EmitsTelemetryOnStatusChange(PackageStatus fromStatus, PackageStatus toStatus) { Package.PackageStatusKey = fromStatus; await Target.SetStatusAsync(PackageValidatingEntity, ValidationSet, toStatus); if (fromStatus != toStatus) { TelemetryServiceMock.Verify( x => x.TrackPackageStatusChange(ValidationSet.PackageId, ValidationSet.PackageNormalizedVersion, ValidationSet.ValidationTrackingId, fromStatus, toStatus), Times.Once); TelemetryServiceMock.Verify( x => x.TrackPackageStatusChange(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Guid>(), It.IsAny <PackageStatus>(), It.IsAny <PackageStatus>()), Times.Once); } else { TelemetryServiceMock.Verify( x => x.TrackPackageStatusChange(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Guid>(), It.IsAny <PackageStatus>(), It.IsAny <PackageStatus>()), Times.Never); } }
public async Task TracksSuccessOnAllRequiredValidatorsFinished(bool requiredValidationSucceeded, bool expectedCompletionTracking) { AddValidation("requiredValidation", ValidationStatus.Succeeded, ValidationFailureBehavior.MustSucceed); AddValidation("optionalValidaiton", ValidationStatus.Incomplete, ValidationFailureBehavior.AllowedToFail); ProcessorStats.AnyRequiredValidationSucceeded = requiredValidationSucceeded; var processor = CreateProcessor(); await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); if (expectedCompletionTracking) { TelemetryServiceMock .Verify(ts => ts.TrackTotalValidationDuration(It.IsAny <TimeSpan>(), true), Times.Once()); TelemetryServiceMock .Verify(ts => ts.TrackTotalValidationDuration(It.IsAny <TimeSpan>(), It.IsAny <bool>()), Times.Once()); } else { TelemetryServiceMock .Verify(ts => ts.TrackTotalValidationDuration(It.IsAny <TimeSpan>(), It.IsAny <bool>()), Times.Never()); } }
public async Task StartsNotStartedValidations(ValidationStatus startStatus, bool expectStorageUpdate, bool expectCleanup) { UseDefaultValidatorProvider(); const string validationName = "validation1"; var validator = AddValidation(validationName, TimeSpan.FromDays(1)); var validation = ValidationSet.PackageValidations.First(); ValidationStatus actualStatus = ValidationStatus.NotStarted; validator .Setup(v => v.GetResultAsync(It.IsAny <IValidationRequest>())) .ReturnsAsync(new ValidationResult(actualStatus)) .Callback <IValidationRequest>(r => Assert.Equal(validation.Key, r.ValidationId)); validator .Setup(v => v.StartAsync(It.IsAny <IValidationRequest>())) .ReturnsAsync(new ValidationResult(startStatus)) .Callback <IValidationRequest>(r => { Assert.Equal(validation.Key, r.ValidationId); actualStatus = startStatus; }) .Verifiable(); ValidationStorageMock .Setup(vs => vs.MarkValidationStartedAsync(validation, It.Is <ValidationResult>(r => r.Status == startStatus))) .Returns(Task.FromResult(0)) .Callback <PackageValidation, ValidationResult>((pv, vr) => pv.ValidationStatus = vr.Status) .Verifiable(); var processor = CreateProcessor(); await processor.ProcessValidationsAsync(ValidationSet, Package); validator.Verify(v => v.StartAsync(It.IsAny <IValidationRequest>()), Times.AtLeastOnce()); if (expectStorageUpdate) { ValidationStorageMock.Verify( vs => vs.MarkValidationStartedAsync(validation, It.Is <ValidationResult>(r => r.Status == startStatus)), Times.Once); ValidationStorageMock.Verify( vs => vs.MarkValidationStartedAsync(It.IsAny <PackageValidation>(), It.IsAny <ValidationResult>()), Times.Once); TelemetryServiceMock.Verify( ts => ts.TrackValidatorStarted(validationName), Times.Once); TelemetryServiceMock.Verify( ts => ts.TrackValidatorStarted(It.IsAny <string>()), Times.Once); } else { ValidationStorageMock.Verify( vs => vs.MarkValidationStartedAsync(It.IsAny <PackageValidation>(), It.IsAny <ValidationResult>()), Times.Never); TelemetryServiceMock.Verify( ts => ts.TrackValidatorStarted(It.IsAny <string>()), Times.Never); } if (expectCleanup) { validator.Verify( x => x.CleanUpAsync(It.IsAny <IValidationRequest>()), Times.Once); } else { validator.Verify( x => x.CleanUpAsync(It.IsAny <IValidationRequest>()), Times.Never); } }
public async Task DoesNotCreateValidationsWhenShouldStartFalse() { const string validation1 = "validation1"; const string validation2 = "validation2"; Configuration.Validations = new List <ValidationConfigurationItem> { new ValidationConfigurationItem() { Name = validation1, TrackAfter = TimeSpan.FromDays(1), RequiredValidations = new List <string>(), ShouldStart = true, }, new ValidationConfigurationItem() { Name = validation2, TrackAfter = TimeSpan.FromDays(1), RequiredValidations = new List <string>(), ShouldStart = false, } }; Guid validationTrackingId = Guid.NewGuid(); ValidationStorageMock .Setup(vs => vs.GetValidationSetAsync(validationTrackingId)) .ReturnsAsync((PackageValidationSet)null) .Verifiable(); ValidationStorageMock .Setup(vs => vs.OtherRecentValidationSetForPackageExists(It.IsAny <IValidatingEntity <Package> >(), It.IsAny <TimeSpan>(), validationTrackingId)) .ReturnsAsync(false); PackageValidationSet createdSet = null; ValidationStorageMock .Setup(vs => vs.CreateValidationSetAsync(It.IsAny <PackageValidationSet>())) .Returns <PackageValidationSet>(pvs => Task.FromResult(pvs)) .Callback <PackageValidationSet>(pvs => createdSet = pvs) .Verifiable(); ValidationStorageMock .Setup(vs => vs.GetValidationSetCountAsync(It.IsAny <IValidatingEntity <Package> >())) .ReturnsAsync(1); var provider = new ValidationSetProvider <Package>( ValidationStorageMock.Object, PackageFileServiceMock.Object, ValidatorProvider.Object, ConfigurationAccessorMock.Object, TelemetryServiceMock.Object, LoggerMock.Object); var packageValidationMessageData = new ProcessValidationSetData( Package.PackageRegistration.Id, Package.NormalizedVersion, validationTrackingId, ValidatingType.Package, Package.Key); var returnedSet = await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, PackageValidatingEntity); var endOfCallTimestamp = DateTime.UtcNow; ValidationStorageMock .Verify(vs => vs.CreateValidationSetAsync(It.IsAny <PackageValidationSet>()), Times.Once); Assert.NotNull(returnedSet); Assert.NotNull(createdSet); Assert.Same(createdSet, returnedSet); Assert.Equal(Package.PackageRegistration.Id, createdSet.PackageId); Assert.Equal(Package.NormalizedVersion, createdSet.PackageNormalizedVersion); Assert.Equal(Package.Key, createdSet.PackageKey); Assert.Equal(validationTrackingId, createdSet.ValidationTrackingId); Assert.True(createdSet.Created.Kind == DateTimeKind.Utc); Assert.True(createdSet.Updated.Kind == DateTimeKind.Utc); var allowedTimeDifference = TimeSpan.FromSeconds(5); Assert.True(endOfCallTimestamp - createdSet.Created < allowedTimeDifference); Assert.True(endOfCallTimestamp - createdSet.Updated < allowedTimeDifference); Assert.All(createdSet.PackageValidations, v => Assert.Same(createdSet, v.PackageValidationSet)); Assert.All(createdSet.PackageValidations, v => Assert.Equal(ValidationStatus.NotStarted, v.ValidationStatus)); Assert.All(createdSet.PackageValidations, v => Assert.True(endOfCallTimestamp - v.ValidationStatusTimestamp < allowedTimeDifference)); Assert.Contains(createdSet.PackageValidations, v => v.Type == validation1); Assert.DoesNotContain(createdSet.PackageValidations, v => v.Type == validation2); PackageFileServiceMock.Verify( x => x.CopyValidationPackageForValidationSetAsync(returnedSet), Times.Once); TelemetryServiceMock.Verify( x => x.TrackDurationToValidationSetCreation(createdSet.PackageId, createdSet.PackageNormalizedVersion, createdSet.ValidationTrackingId, createdSet.Created - Package.Created), Times.Once); }