public async Task DropsMessageIfPackageIsSoftDeletedForProcessValidationSet() { var messageData = PackageValidationMessageData.NewProcessValidationSet( "packageId", "1.2.3", Guid.NewGuid(), ValidatingType.Package, entityKey: null); var validationConfiguration = new ValidationConfiguration(); var package = new Package { PackageStatusKey = PackageStatus.Deleted }; var packageValidatingEntity = new PackageValidatingEntity(package); CorePackageServiceMock .Setup(ps => ps.FindPackageByIdAndVersionStrict( messageData.ProcessValidationSet.PackageId, messageData.ProcessValidationSet.PackageVersion)) .Returns(packageValidatingEntity); var handler = CreateHandler(); var result = await handler.HandleAsync(messageData); Assert.True(result); CorePackageServiceMock.Verify( ps => ps.FindPackageByIdAndVersionStrict( messageData.ProcessValidationSet.PackageId, messageData.ProcessValidationSet.PackageVersion), Times.Once); }
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); }
private async Task <StartRevalidationResult> StartRevalidationsAsync(IReadOnlyList <PackageRevalidation> revalidations) { _logger.LogInformation("Starting {RevalidationCount} revalidations...", revalidations.Count); foreach (var revalidation in revalidations) { _logger.LogInformation( "Starting revalidation for package {PackageId} {PackageVersion}...", revalidation.PackageId, revalidation.PackageNormalizedVersion); var message = PackageValidationMessageData.NewProcessValidationSet( revalidation.PackageId, revalidation.PackageNormalizedVersion, revalidation.ValidationTrackingId.Value, ValidatingType.Package, entityKey: null); await _validationEnqueuer.SendMessageAsync(message); _telemetryService.TrackPackageRevalidationStarted(revalidation.PackageId, revalidation.PackageNormalizedVersion); _logger.LogInformation( "Started revalidation for package {PackageId} {PackageVersion}", revalidation.PackageId, revalidation.PackageNormalizedVersion); } _logger.LogInformation("Started {RevalidationCount} revalidations, marking them as enqueued...", revalidations.Count); await _packageState.MarkPackageRevalidationsAsEnqueuedAsync(revalidations); _logger.LogInformation("Marked {RevalidationCount} revalidations as enqueued", revalidations.Count); return(StartRevalidationResult.RevalidationsEnqueued(revalidations.Count)); }
public async Task WaitsForPackageAvailabilityInGalleryDBWithProcessValidationSet() { var messageData = PackageValidationMessageData.NewProcessValidationSet( "packageId", "1.2.3", Guid.NewGuid(), ValidatingType.Package, entityKey: null); var validationConfiguration = new ValidationConfiguration(); CorePackageServiceMock .Setup(ps => ps.FindPackageByIdAndVersionStrict( messageData.ProcessValidationSet.PackageId, messageData.ProcessValidationSet.PackageVersion)) .Returns <Package>(null) .Verifiable(); var handler = CreateHandler(); await handler.HandleAsync(messageData); CorePackageServiceMock.Verify( ps => ps.FindPackageByIdAndVersionStrict( messageData.ProcessValidationSet.PackageId, messageData.ProcessValidationSet.PackageVersion), Times.Once); }
public async Task <PackageStatus> StartValidationAsync(TPackageEntity package) { var validatingType = ValidateAndGetType(package); var entityKey = package.Key == default(int) ? (int?)null : package.Key; var data = PackageValidationMessageData.NewProcessValidationSet( package.Id, package.Version, Guid.NewGuid(), validatingType, entityKey: entityKey); var activityName = $"Enqueuing asynchronous package validation: " + $"{data.ProcessValidationSet.PackageId} {data.ProcessValidationSet.PackageVersion} " + $"{data.ProcessValidationSet.ValidatingType} ({data.ProcessValidationSet.ValidationTrackingId})"; using (_diagnosticsSource.Activity(activityName)) { var postponeProcessingTill = DateTimeOffset.UtcNow + _appConfiguration.AsynchronousPackageValidationDelay; await _validationEnqueuer.SendMessageAsync(data, postponeProcessingTill); } return(TargetPackageStatus); }
public HandleProcessValidationSetAsync(ITestOutputHelper output) : base(output) { Message = PackageValidationMessageData.NewProcessValidationSet( ValidationSet.PackageId, ValidationSet.PackageNormalizedVersion, ValidationSet.ValidationTrackingId, ValidationSet.ValidatingType, ValidationSet.PackageKey); ValidationSetProvider .Setup(x => x.TryGetOrCreateValidationSetAsync( It.IsAny <ProcessValidationSetData>(), It.IsAny <IValidatingEntity <TestEntity> >())) .ReturnsAsync(() => ValidationSet); }
public async Task DropsMessageOnDuplicateValidationRequest() { var messageData = PackageValidationMessageData.NewProcessValidationSet( "packageId", "1.2.3", Guid.NewGuid(), ValidatingType.SymbolPackage, entityKey: null); var validationConfiguration = new ValidationConfiguration(); var symbolPackage = new SymbolPackage() { Package = new Package() }; var symbolPackageValidatingEntity = new SymbolPackageValidatingEntity(symbolPackage); CoreSymbolPackageServiceMock .Setup(ps => ps.FindPackageByIdAndVersionStrict( messageData.ProcessValidationSet.PackageId, messageData.ProcessValidationSet.PackageVersion)) .Returns(symbolPackageValidatingEntity) .Verifiable(); ValidationSetProviderMock .Setup(vsp => vsp.TryGetOrCreateValidationSetAsync(messageData.ProcessValidationSet, symbolPackageValidatingEntity)) .ReturnsAsync((PackageValidationSet)null) .Verifiable(); var handler = CreateHandler(); var result = await handler.HandleAsync(messageData); Assert.True(result); CoreSymbolPackageServiceMock.Verify( ps => ps.FindPackageByIdAndVersionStrict( messageData.ProcessValidationSet.PackageId, messageData.ProcessValidationSet.PackageVersion), Times.Once); ValidationSetProviderMock.Verify( vsp => vsp.TryGetOrCreateValidationSetAsync( messageData.ProcessValidationSet, symbolPackageValidatingEntity), Times.Once); }
public void ProducesExpectedMessageForPackageProcessValidationSet() { // Arrange var input = PackageValidationMessageData.NewProcessValidationSet( PackageId, PackageVersion, ValidationTrackingId, ValidatingType.Package, PackageKey); // Act var output = _target.SerializePackageValidationMessageData(input); // Assert Assert.Contains(SchemaVersionKey, output.Properties.Keys); Assert.Equal(SchemaVersion1, output.Properties[SchemaVersionKey]); Assert.Contains(SchemaName, output.Properties.Keys); Assert.Equal(ProcessValidationSetType, output.Properties[SchemaName]); var body = output.GetBody(); Assert.Equal(TestData.SerializedProcessValidationSetDataPackage, body); }
private async Task ScheduleCheckIfNotTimedOut( PackageValidationSet validationSet, IValidatingEntity <T> validatingEntity, bool scheduleNextCheck, bool tooLongNotificationAllowed) { var validationSetDuration = await UpdateValidationDurationAsync(validationSet, validatingEntity, tooLongNotificationAllowed); // Schedule another check if we haven't reached the validation set timeout yet. if (validationSetDuration <= _validationConfiguration.TimeoutValidationSetAfter) { if (scheduleNextCheck) { var messageData = PackageValidationMessageData.NewProcessValidationSet( validationSet.PackageId, validationSet.PackageNormalizedVersion, validationSet.ValidationTrackingId, validationSet.ValidatingType, entityKey: validationSet.PackageKey); var postponeUntil = DateTimeOffset.UtcNow + _validationConfiguration.ValidationMessageRecheckPeriod; await _validationEnqueuer.SendMessageAsync(messageData, postponeUntil); } } else { _logger.LogWarning("Abandoning checking status of validation set {ValidationTrackingId} for " + "package {PackageId} {PackageVersion} because it took too long (Duration: {Duration}, CutOffDuration: {CutOffDuration})", validationSet.ValidationTrackingId, validationSet.PackageId, validationSet.PackageNormalizedVersion, validationSetDuration, _validationConfiguration.TimeoutValidationSetAfter); _telemetryService.TrackValidationSetTimeout(validationSet.PackageId, validationSet.PackageNormalizedVersion, validationSet.ValidationTrackingId); } }
private async Task <bool> ProcessValidationSetAsync(ProcessValidationSetData message, int deliveryCount) { using (_logger.BeginScope( "Handling process validation set message for {ValidatingType} {PackageId} {PackageVersion} {Key} " + "{ValidationSetId}", ValidatingType, message.PackageId, message.PackageNormalizedVersion, message.EntityKey, message.ValidationTrackingId)) { // When a message is sent from the Gallery with validation of a new entity, the EntityKey will be null // because the message is sent to the service bus before the entity is persisted in the DB. However // when a revalidation happens or when the message is re-sent by the orchestrator the message will // contain the key. In this case the key is used to find the entity to validate. var entity = message.EntityKey.HasValue ? _entityService.FindPackageByKey(message.EntityKey.Value) : _entityService.FindPackageByIdAndVersionStrict(message.PackageId, message.PackageNormalizedVersion); if (entity == null) { // no package in DB yet. Might have received message a bit early, need to retry later if (deliveryCount - 1 >= _configs.MissingPackageRetryCount) { _logger.LogWarning( "Could not find {ValidatingType} {PackageId} {PackageVersion} {Key} in DB after " + "{DeliveryCount} tries. Discarding the message.", ValidatingType, message.PackageId, message.PackageNormalizedVersion, message.EntityKey, deliveryCount); _telemetryService.TrackMissingPackageForValidationMessage( message.PackageId, message.PackageNormalizedVersion, message.ValidationTrackingId.ToString()); return(true); } else { _logger.LogInformation( "Could not find {ValidatingType} {PackageId} {PackageVersion} {Key} in DB. Retrying.", ValidatingType, message.PackageId, message.PackageNormalizedVersion, message.EntityKey); return(false); } } // Immediately halt validation of a soft deleted package. if (ShouldNoOpDueToDeletion && entity.Status == PackageStatus.Deleted) { _logger.LogWarning( "{ValidatingType} {PackageId} {PackageNormalizedVersion} {Key} is soft deleted. Dropping " + "message for validation set {ValidationSetId}.", ValidatingType, message.PackageId, message.PackageNormalizedVersion, entity.Key, message.ValidationTrackingId); return(true); } var lease = await TryAcquireLeaseAsync(message.PackageId, message.PackageNormalizedVersion); if (lease.State == LeaseContextState.Unavailable) { _logger.LogInformation( "The lease {ResourceName} is unavailable. Retrying this message in {LeaseTime}.", lease.ResourceName, LeaseTime); var messageData = PackageValidationMessageData.NewProcessValidationSet( message.PackageId, message.PackageNormalizedVersion, message.ValidationTrackingId, message.ValidatingType, message.EntityKey); var postponeUntil = DateTimeOffset.UtcNow + LeaseTime; await _validationEnqueuer.SendMessageAsync(messageData, postponeUntil); return(true); } try { var validationSet = await _validationSetProvider.TryGetOrCreateValidationSetAsync(message, entity); if (validationSet == null) { _logger.LogInformation( "The validation request for {ValidatingType} {PackageId} {PackageVersion} {Key} " + "{ValidationSetId} is a duplicate. Discarding the message.", ValidatingType, message.PackageId, message.PackageNormalizedVersion, entity.Key, message.ValidationTrackingId); return(true); } await ProcessValidationSetAsync(entity, validationSet, scheduleNextCheck : true); } finally { await TryReleaseLeaseAsync(lease); } } return(true); }