From 5e028e3bf348a96193488213e824ac322e7cf54d Mon Sep 17 00:00:00 2001 From: Joel Verhagen Date: Mon, 22 Jul 2019 13:44:51 -0700 Subject: [PATCH] Handle "check validator" message in orchestrator (#779) Address https://github.com/NuGet/NuGetGallery/issues/7354 --- .../Gallery.CredentialExpiration.csproj | 2 +- .../NuGet.Jobs.Common.csproj | 10 +- .../NuGet.Services.Revalidate.csproj | 2 +- .../Services/RevalidationStarter.cs | 6 +- .../IValidationOutcomeProcessor.cs | 7 +- .../IValidationSetProvider.cs | 11 +- .../IValidationStorageService.cs | 8 + .../Job.cs | 3 +- .../PackageValidationMessageHandler.cs | 112 +++++++- .../SymbolValidationMessageHandler.cs | 101 +++++-- .../ValidationOutcomeProcessor.cs | 43 ++- .../ValidationSetProvider.cs | 9 +- .../ValidationStorageService.cs | 15 + src/PackageHash/PackageHash.csproj | 2 +- .../Monitoring.PackageLag.csproj | 2 +- src/StatusAggregator/StatusAggregator.csproj | 6 +- .../PackageDownloaderConfiguration.cs | 0 .../SubscriptionProcessorConfiguration.cs | 0 .../Validation.Common.Job.csproj | 12 +- .../Validation.ScanAndSign.Core.csproj | 2 +- .../Services/RevalidationStarterFacts.cs | 9 +- .../SymbolValidationMessageHandlerFacts.cs | 206 ++++++++++++-- .../ValidationMessageHandlerFacts.cs | 259 +++++++++++++++--- .../ValidationOutcomeProcessorFacts.cs | 77 ++++-- .../ValidationSetProviderFacts.cs | 57 ++-- .../ValidationStorageServiceFacts.cs | 35 +++ 26 files changed, 815 insertions(+), 181 deletions(-) rename src/Validation.Common.Job/{ => Configuration}/PackageDownloaderConfiguration.cs (100%) rename src/Validation.Common.Job/{ => Configuration}/SubscriptionProcessorConfiguration.cs (100%) diff --git a/src/Gallery.CredentialExpiration/Gallery.CredentialExpiration.csproj b/src/Gallery.CredentialExpiration/Gallery.CredentialExpiration.csproj index 171988ecf..6252e1088 100644 --- a/src/Gallery.CredentialExpiration/Gallery.CredentialExpiration.csproj +++ b/src/Gallery.CredentialExpiration/Gallery.CredentialExpiration.csproj @@ -91,7 +91,7 @@ 5.8.4 - 2.52.0 + 2.53.0 diff --git a/src/NuGet.Jobs.Common/NuGet.Jobs.Common.csproj b/src/NuGet.Jobs.Common/NuGet.Jobs.Common.csproj index 2a24c73f1..5845aab24 100644 --- a/src/NuGet.Jobs.Common/NuGet.Jobs.Common.csproj +++ b/src/NuGet.Jobs.Common/NuGet.Jobs.Common.csproj @@ -107,19 +107,19 @@ all - 2.52.0 + 2.53.0 - 2.52.0 + 2.53.0 - 2.52.0 + 2.53.0 - 2.52.0 + 2.53.0 - 2.52.0 + 2.53.0 diff --git a/src/NuGet.Services.Revalidate/NuGet.Services.Revalidate.csproj b/src/NuGet.Services.Revalidate/NuGet.Services.Revalidate.csproj index 50a4c396b..2958084ec 100644 --- a/src/NuGet.Services.Revalidate/NuGet.Services.Revalidate.csproj +++ b/src/NuGet.Services.Revalidate/NuGet.Services.Revalidate.csproj @@ -118,7 +118,7 @@ all - 2.52.0 + 2.53.0 diff --git a/src/NuGet.Services.Revalidate/Services/RevalidationStarter.cs b/src/NuGet.Services.Revalidate/Services/RevalidationStarter.cs index d743f2d38..a3dfb4a3b 100644 --- a/src/NuGet.Services.Revalidate/Services/RevalidationStarter.cs +++ b/src/NuGet.Services.Revalidate/Services/RevalidationStarter.cs @@ -141,10 +141,12 @@ private async Task StartRevalidationsAsync(IReadOnlyLis revalidation.PackageId, revalidation.PackageNormalizedVersion); - var message = new PackageValidationMessageData( + var message = PackageValidationMessageData.NewProcessValidationSet( revalidation.PackageId, revalidation.PackageNormalizedVersion, - revalidation.ValidationTrackingId.Value); + revalidation.ValidationTrackingId.Value, + ValidatingType.Package, + entityKey: null); await _validationEnqueuer.StartValidationAsync(message); diff --git a/src/NuGet.Services.Validation.Orchestrator/IValidationOutcomeProcessor.cs b/src/NuGet.Services.Validation.Orchestrator/IValidationOutcomeProcessor.cs index c75b13ccb..97514ade3 100644 --- a/src/NuGet.Services.Validation.Orchestrator/IValidationOutcomeProcessor.cs +++ b/src/NuGet.Services.Validation.Orchestrator/IValidationOutcomeProcessor.cs @@ -21,7 +21,12 @@ public interface IValidationOutcomeProcessor where T : class, IEntity /// The validating entity. /// Contains information about what happened during current message processing in /// the validation set processor. + /// Whether or not the next check should be scheduled. /// A task that completes when the outcome has been processed - Task ProcessValidationOutcomeAsync(PackageValidationSet validationSet, IValidatingEntity validatingEntity, ValidationSetProcessorResult currentCallStats); + Task ProcessValidationOutcomeAsync( + PackageValidationSet validationSet, + IValidatingEntity validatingEntity, + ValidationSetProcessorResult currentCallStats, + bool scheduleNextCheck); } } diff --git a/src/NuGet.Services.Validation.Orchestrator/IValidationSetProvider.cs b/src/NuGet.Services.Validation.Orchestrator/IValidationSetProvider.cs index fe15e192a..4e660ab80 100644 --- a/src/NuGet.Services.Validation.Orchestrator/IValidationSetProvider.cs +++ b/src/NuGet.Services.Validation.Orchestrator/IValidationSetProvider.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Threading.Tasks; using NuGet.Services.Entities; @@ -20,6 +21,14 @@ public interface IValidationSetProvider where T : class, IEntity /// requested . Null if no further processing /// should be made (e.g. duplicate validation request was detected). /// - Task TryGetOrCreateValidationSetAsync(PackageValidationMessageData message, IValidatingEntity validatingEntity); + Task TryGetOrCreateValidationSetAsync(ProcessValidationSetData message, IValidatingEntity validatingEntity); + + /// + /// Reads a validation set from storage based given and ID of one of the validations in the set. If no such + /// validation exists, null is returned. + /// + /// The validation ID. + /// The validation set, or null. + Task TryGetParentValidationSetAsync(Guid validationId); } } diff --git a/src/NuGet.Services.Validation.Orchestrator/IValidationStorageService.cs b/src/NuGet.Services.Validation.Orchestrator/IValidationStorageService.cs index ab15a5d89..5e7ddcc23 100644 --- a/src/NuGet.Services.Validation.Orchestrator/IValidationStorageService.cs +++ b/src/NuGet.Services.Validation.Orchestrator/IValidationStorageService.cs @@ -26,6 +26,14 @@ public interface IValidationStorageService /// Validation set instance if found, null otherwise. Task GetValidationSetAsync(Guid validationTrackingId); + /// + /// Reads a validation set from storage based given and ID of one of the validations in the set. If no such + /// validation exists, null is returned. + /// + /// The validation ID. + /// The validation set, or null. + Task TryGetParentValidationSetAsync(Guid validationId); + /// /// Gets the number of validation sets that the provided entity has. /// diff --git a/src/NuGet.Services.Validation.Orchestrator/Job.cs b/src/NuGet.Services.Validation.Orchestrator/Job.cs index 4c3e1af99..78be2fe52 100644 --- a/src/NuGet.Services.Validation.Orchestrator/Job.cs +++ b/src/NuGet.Services.Validation.Orchestrator/Job.cs @@ -314,8 +314,7 @@ private static IServiceProvider CreateProvider(IServiceCollection services, ICon (pi, ctx) => ctx.ResolveKeyed(PackageVerificationTopicClientBindingKey))) .WithParameter(new ResolvedParameter( (pi, ctx) => pi.ParameterType == typeof(IBrokeredMessageSerializer), - (pi, ctx) => ctx.Resolve() - )) + (pi, ctx) => ctx.Resolve())) .As(); containerBuilder diff --git a/src/NuGet.Services.Validation.Orchestrator/PackageValidationMessageHandler.cs b/src/NuGet.Services.Validation.Orchestrator/PackageValidationMessageHandler.cs index 5cccc9eef..bc7efa691 100644 --- a/src/NuGet.Services.Validation.Orchestrator/PackageValidationMessageHandler.cs +++ b/src/NuGet.Services.Validation.Orchestrator/PackageValidationMessageHandler.cs @@ -65,6 +65,74 @@ public async Task HandleAsync(PackageValidationMessageData message) throw new ArgumentNullException(nameof(message)); } + switch (message.Type) + { + case PackageValidationMessageType.CheckValidator: + return await CheckValidatorAsync(message.CheckValidator); + case PackageValidationMessageType.ProcessValidationSet: + return await ProcessValidationSetAsync(message.ProcessValidationSet, message.DeliveryCount); + default: + throw new NotSupportedException($"The package validation message type '{message.Type}' is not supported."); + } + } + + private async Task CheckValidatorAsync(CheckValidatorData message) + { + PackageValidationSet validationSet; + IValidatingEntity package; + using (_logger.BeginScope("Finding validation set and package for validation ID {ValidationId}", message.ValidationId)) + { + validationSet = await _validationSetProvider.TryGetParentValidationSetAsync(message.ValidationId); + if (validationSet == null) + { + _logger.LogError("Could not find validation set for {ValidationId}.", message.ValidationId); + return false; + } + + if (validationSet.ValidatingType != ValidatingType.Package) + { + _logger.LogError("Validation set {ValidationSetId} is not for a package.", message.ValidationId); + return false; + } + + package = _galleryPackageService.FindPackageByKey(validationSet.PackageKey); + if (package == null) + { + _logger.LogError( + "Could not find package {PackageId} {PackageVersion} for validation set {ValidationSetId}.", + validationSet.PackageId, + validationSet.PackageNormalizedVersion, + validationSet.ValidationTrackingId); + return false; + } + + // Immediately halt validation of a soft deleted package. + if (package.Status == PackageStatus.Deleted) + { + _logger.LogWarning( + "Package {PackageId} {PackageNormalizedVersion} (package key {PackageKey}) is soft deleted. Dropping message for validation set {ValidationSetId}.", + validationSet.PackageId, + validationSet.PackageNormalizedVersion, + package.Key, + validationSet.ValidationTrackingId); + + return true; + } + } + + using (_logger.BeginScope("Handling check validator message for {PackageId} {PackageVersion} validation set {ValidationSetId}", + validationSet.PackageId, + validationSet.PackageNormalizedVersion, + validationSet.ValidationTrackingId)) + { + await ProcessValidationSetAsync(package, validationSet, scheduleNextCheck: false); + } + + return true; + } + + private async Task ProcessValidationSetAsync(ProcessValidationSetData message, int deliveryCount) + { using (_logger.BeginScope("Handling message for {PackageId} {PackageVersion} validation set {ValidationSetId}", message.PackageId, message.PackageNormalizedVersion, @@ -75,12 +143,12 @@ public async Task HandleAsync(PackageValidationMessageData message) if (package == null) { // no package in DB yet. Might have received message a bit early, need to retry later - if (message.DeliveryCount - 1 >= _configs.MissingPackageRetryCount) + if (deliveryCount - 1 >= _configs.MissingPackageRetryCount) { _logger.LogWarning("Could not find package {PackageId} {PackageNormalizedVersion} in DB after {DeliveryCount} tries, dropping message", message.PackageId, message.PackageNormalizedVersion, - message.DeliveryCount); + deliveryCount); _telemetryService.TrackMissingPackageForValidationMessage( message.PackageId, @@ -125,21 +193,35 @@ public async Task HandleAsync(PackageValidationMessageData message) return true; } - if (validationSet.ValidationSetStatus == ValidationSetStatus.Completed) - { - _logger.LogInformation( - "The validation set {PackageId} {PackageNormalizedVersion} {ValidationSetId} is already " + - "completed. Discarding the message.", - message.PackageId, - message.PackageNormalizedVersion, - message.ValidationTrackingId); - return true; - } - - var processorStats = await _validationSetProcessor.ProcessValidationsAsync(validationSet); - await _validationOutcomeProcessor.ProcessValidationOutcomeAsync(validationSet, package, processorStats); + await ProcessValidationSetAsync(package, validationSet, scheduleNextCheck: true); } + return true; } + + private async Task ProcessValidationSetAsync( + IValidatingEntity package, + PackageValidationSet validationSet, + bool scheduleNextCheck) + { + if (validationSet.ValidationSetStatus == ValidationSetStatus.Completed) + { + _logger.LogInformation( + "The validation set {PackageId} {PackageNormalizedVersion} {ValidationSetId} is already " + + "completed. Discarding the message.", + validationSet.PackageId, + validationSet.PackageNormalizedVersion, + validationSet.ValidationTrackingId); + return; + } + + var processorStats = await _validationSetProcessor.ProcessValidationsAsync(validationSet); + + await _validationOutcomeProcessor.ProcessValidationOutcomeAsync( + validationSet, + package, + processorStats, + scheduleNextCheck); + } } } diff --git a/src/NuGet.Services.Validation.Orchestrator/SymbolValidationMessageHandler.cs b/src/NuGet.Services.Validation.Orchestrator/SymbolValidationMessageHandler.cs index 61bb54741..5f77d1d2e 100644 --- a/src/NuGet.Services.Validation.Orchestrator/SymbolValidationMessageHandler.cs +++ b/src/NuGet.Services.Validation.Orchestrator/SymbolValidationMessageHandler.cs @@ -68,6 +68,63 @@ public async Task HandleAsync(PackageValidationMessageData message) throw new ArgumentNullException(nameof(message)); } + switch (message.Type) + { + case PackageValidationMessageType.CheckValidator: + return await CheckValidatorAsync(message.CheckValidator); + case PackageValidationMessageType.ProcessValidationSet: + return await ProcessValidationSetAsync(message.ProcessValidationSet, message.DeliveryCount); + default: + throw new NotSupportedException($"The package validation message type '{message.Type}' is not supported."); + } + } + + private async Task CheckValidatorAsync(CheckValidatorData message) + { + PackageValidationSet validationSet; + IValidatingEntity symbolPackageEntity; + using (_logger.BeginScope("Finding validation set and symbol package for validation ID {ValidationId}", message.ValidationId)) + { + validationSet = await _validationSetProvider.TryGetParentValidationSetAsync(message.ValidationId); + if (validationSet == null) + { + _logger.LogError("Could not find validation set for {ValidationId}.", message.ValidationId); + return false; + } + + if (validationSet.ValidatingType != ValidatingType.SymbolPackage) + { + _logger.LogError("Validation set {ValidationSetId} is not for a symbol package.", message.ValidationId); + return false; + } + + symbolPackageEntity = _gallerySymbolService.FindPackageByKey(validationSet.PackageKey); + if (symbolPackageEntity == null) + { + _logger.LogError( + "Could not find symbol package {PackageId} {PackageVersion} {Key} for validation set {ValidationSetId}.", + validationSet.PackageId, + validationSet.PackageNormalizedVersion, + validationSet.PackageKey, + validationSet.ValidationTrackingId); + return false; + } + } + + using (_logger.BeginScope("Handling check symbol validator message for {PackageId} {PackageVersion} {Key} validation set {ValidationSetId}", + validationSet.PackageId, + validationSet.PackageNormalizedVersion, + validationSet.PackageKey, + validationSet.ValidationTrackingId)) + { + await ProcessValidationSetAsync(symbolPackageEntity, validationSet, scheduleNextCheck: false); + } + + return true; + } + + private async Task ProcessValidationSetAsync(ProcessValidationSetData message, int deliveryCount) + { using (_logger.BeginScope("Handling symbol message for {PackageId} {PackageVersion} validation set {ValidationSetId}", message.PackageId, message.PackageNormalizedVersion, @@ -82,12 +139,12 @@ public async Task HandleAsync(PackageValidationMessageData message) if (symbolPackageEntity == null) { // no package in DB yet. Might have received message a bit early, need to retry later - if (message.DeliveryCount - 1 >= _configs.MissingPackageRetryCount) + if (deliveryCount - 1 >= _configs.MissingPackageRetryCount) { _logger.LogWarning("Could not find symbols for package {PackageId} {PackageNormalizedVersion} in DB after {DeliveryCount} tries, dropping message", message.PackageId, message.PackageNormalizedVersion, - message.DeliveryCount); + deliveryCount); _telemetryService.TrackMissingPackageForValidationMessage( message.PackageId, @@ -120,23 +177,35 @@ public async Task HandleAsync(PackageValidationMessageData message) return true; } - if (validationSet.ValidationSetStatus == ValidationSetStatus.Completed) - { - _logger.LogInformation( - "The validation set {PackageId} {PackageNormalizedVersion} {ValidationSetId} is already " + - "completed. Discarding the message.", - message.PackageId, - message.PackageNormalizedVersion, - message.ValidationTrackingId); - return true; - } - - var processorStats = await _validationSetProcessor.ProcessValidationsAsync(validationSet); - // As part of the processing the validation outcome the orchestrator will send itself a message if validation are still being processed. - await _validationOutcomeProcessor.ProcessValidationOutcomeAsync(validationSet, symbolPackageEntity, processorStats); + await ProcessValidationSetAsync(symbolPackageEntity, validationSet, scheduleNextCheck: true); } return true; } + + private async Task ProcessValidationSetAsync( + IValidatingEntity symbolPackageEntity, + PackageValidationSet validationSet, + bool scheduleNextCheck) + { + if (validationSet.ValidationSetStatus == ValidationSetStatus.Completed) + { + _logger.LogInformation( + "The validation set {PackageId} {PackageNormalizedVersion} {ValidationSetId} is already " + + "completed. Discarding the message.", + validationSet.PackageId, + validationSet.PackageNormalizedVersion, + validationSet.ValidationTrackingId); + return; + } + + var processorStats = await _validationSetProcessor.ProcessValidationsAsync(validationSet); + + await _validationOutcomeProcessor.ProcessValidationOutcomeAsync( + validationSet, + symbolPackageEntity, + processorStats, + scheduleNextCheck); + } } } diff --git a/src/NuGet.Services.Validation.Orchestrator/ValidationOutcomeProcessor.cs b/src/NuGet.Services.Validation.Orchestrator/ValidationOutcomeProcessor.cs index 9533e1008..28e6dda13 100644 --- a/src/NuGet.Services.Validation.Orchestrator/ValidationOutcomeProcessor.cs +++ b/src/NuGet.Services.Validation.Orchestrator/ValidationOutcomeProcessor.cs @@ -52,7 +52,11 @@ public ValidationOutcomeProcessor( _validationConfigurationsByName = _validationConfiguration.Validations.ToDictionary(v => v.Name); } - public async Task ProcessValidationOutcomeAsync(PackageValidationSet validationSet, IValidatingEntity validatingEntity, ValidationSetProcessorResult currentCallStats) + public async Task ProcessValidationOutcomeAsync( + PackageValidationSet validationSet, + IValidatingEntity validatingEntity, + ValidationSetProcessorResult currentCallStats, + bool scheduleNextCheck) { var failedValidations = GetFailedValidations(validationSet); @@ -131,7 +135,11 @@ public async Task ProcessValidationOutcomeAsync(PackageValidationSet validationS if (areOptionalValidationsRunning) { - await ScheduleCheckIfNotTimedOut(validationSet, validatingEntity, tooLongNotificationAllowed: false); + await ScheduleCheckIfNotTimedOut( + validationSet, + validatingEntity, + scheduleNextCheck, + tooLongNotificationAllowed: false); } // TODO: implement delayed cleanup that would allow internal services @@ -140,7 +148,11 @@ public async Task ProcessValidationOutcomeAsync(PackageValidationSet validationS } else { - await ScheduleCheckIfNotTimedOut(validationSet, validatingEntity, tooLongNotificationAllowed: true); + await ScheduleCheckIfNotTimedOut( + validationSet, + validatingEntity, + scheduleNextCheck, + tooLongNotificationAllowed: true); } } @@ -276,22 +288,29 @@ await _validationStorageService.GetValidationSetCountAsync(validatingEntity) == return validationSetDuration; } - private async Task ScheduleCheckIfNotTimedOut(PackageValidationSet validationSet, IValidatingEntity validatingEntity, bool tooLongNotificationAllowed) + private async Task ScheduleCheckIfNotTimedOut( + PackageValidationSet validationSet, + IValidatingEntity 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) { - var messageData = new PackageValidationMessageData( - validationSet.PackageId, - validationSet.PackageNormalizedVersion, - validationSet.ValidationTrackingId, - validationSet.ValidatingType, - entityKey: validationSet.PackageKey); - var postponeUntil = DateTimeOffset.UtcNow + _validationConfiguration.ValidationMessageRecheckPeriod; + 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.StartValidationAsync(messageData, postponeUntil); + await _validationEnqueuer.StartValidationAsync(messageData, postponeUntil); + } } else { diff --git a/src/NuGet.Services.Validation.Orchestrator/ValidationSetProvider.cs b/src/NuGet.Services.Validation.Orchestrator/ValidationSetProvider.cs index 3bd75831d..5e369c8d0 100644 --- a/src/NuGet.Services.Validation.Orchestrator/ValidationSetProvider.cs +++ b/src/NuGet.Services.Validation.Orchestrator/ValidationSetProvider.cs @@ -41,7 +41,12 @@ public ValidationSetProvider( _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } - public async Task TryGetOrCreateValidationSetAsync(PackageValidationMessageData message, IValidatingEntity validatingEntity) + public async Task TryGetParentValidationSetAsync(Guid validationId) + { + return await _validationStorageService.TryGetParentValidationSetAsync(validationId); + } + + public async Task TryGetOrCreateValidationSetAsync(ProcessValidationSetData message, IValidatingEntity validatingEntity) { var validationSet = await _validationStorageService.GetValidationSetAsync(message.ValidationTrackingId); @@ -129,7 +134,7 @@ private async Task PersistValidationSetAsync(PackageValida return persistedValidationSet; } - private PackageValidationSet InitializeValidationSet(PackageValidationMessageData message, IValidatingEntity validatingEntity) + private PackageValidationSet InitializeValidationSet(ProcessValidationSetData message, IValidatingEntity validatingEntity) { // If message would have the package Key the package will not need to be passed as an argument _logger.LogInformation("Initializing validation set {ValidationSetId} for package {PackageId} {PackageVersion} (package key {PackageKey})", diff --git a/src/NuGet.Services.Validation.Orchestrator/ValidationStorageService.cs b/src/NuGet.Services.Validation.Orchestrator/ValidationStorageService.cs index 24c5fbec3..5cd5d1256 100644 --- a/src/NuGet.Services.Validation.Orchestrator/ValidationStorageService.cs +++ b/src/NuGet.Services.Validation.Orchestrator/ValidationStorageService.cs @@ -46,6 +46,21 @@ public async Task GetValidationSetAsync(Guid validationTra .FirstOrDefaultAsync(vs => vs.ValidationTrackingId == validationTrackingId); } + public async Task TryGetParentValidationSetAsync(Guid validationId) + { + var packageValidation = await _validationContext + .PackageValidations + .Include(x => x.PackageValidationSet) + .FirstOrDefaultAsync(x => x.Key == validationId); + + if (packageValidation == null) + { + return null; + } + + return packageValidation.PackageValidationSet; + } + public async Task CreateValidationSetAsync(PackageValidationSet packageValidationSet) { packageValidationSet = packageValidationSet ?? throw new ArgumentNullException(nameof(packageValidationSet)); diff --git a/src/PackageHash/PackageHash.csproj b/src/PackageHash/PackageHash.csproj index 2b0a6564b..1d7dbb499 100644 --- a/src/PackageHash/PackageHash.csproj +++ b/src/PackageHash/PackageHash.csproj @@ -75,7 +75,7 @@ - 2.52.0 + 2.53.0 diff --git a/src/PackageLagMonitor/Monitoring.PackageLag.csproj b/src/PackageLagMonitor/Monitoring.PackageLag.csproj index fc9e5550e..6a9d2b5a4 100644 --- a/src/PackageLagMonitor/Monitoring.PackageLag.csproj +++ b/src/PackageLagMonitor/Monitoring.PackageLag.csproj @@ -108,7 +108,7 @@ 0.5.0-CI-20180510-012541 - 2.52.0 + 2.53.0 0.3.0 diff --git a/src/StatusAggregator/StatusAggregator.csproj b/src/StatusAggregator/StatusAggregator.csproj index 46c7f03af..550647b6e 100644 --- a/src/StatusAggregator/StatusAggregator.csproj +++ b/src/StatusAggregator/StatusAggregator.csproj @@ -157,13 +157,13 @@ 1.1.1 - 2.52.0 + 2.53.0 - 2.52.0 + 2.53.0 - 2.52.0 + 2.53.0 0.3.0 diff --git a/src/Validation.Common.Job/PackageDownloaderConfiguration.cs b/src/Validation.Common.Job/Configuration/PackageDownloaderConfiguration.cs similarity index 100% rename from src/Validation.Common.Job/PackageDownloaderConfiguration.cs rename to src/Validation.Common.Job/Configuration/PackageDownloaderConfiguration.cs diff --git a/src/Validation.Common.Job/SubscriptionProcessorConfiguration.cs b/src/Validation.Common.Job/Configuration/SubscriptionProcessorConfiguration.cs similarity index 100% rename from src/Validation.Common.Job/SubscriptionProcessorConfiguration.cs rename to src/Validation.Common.Job/Configuration/SubscriptionProcessorConfiguration.cs diff --git a/src/Validation.Common.Job/Validation.Common.Job.csproj b/src/Validation.Common.Job/Validation.Common.Job.csproj index a5944aed7..9d29f9a79 100644 --- a/src/Validation.Common.Job/Validation.Common.Job.csproj +++ b/src/Validation.Common.Job/Validation.Common.Job.csproj @@ -51,7 +51,7 @@ - + @@ -67,7 +67,7 @@ - + @@ -101,16 +101,16 @@ 5.0.0-preview1.5707 - 2.52.0 + 2.53.0 - 2.52.0 + 2.53.0 - 2.52.0 + 2.53.0 - 2.52.0 + 2.53.0 4.4.5-dev-2873549 diff --git a/src/Validation.ScanAndSign.Core/Validation.ScanAndSign.Core.csproj b/src/Validation.ScanAndSign.Core/Validation.ScanAndSign.Core.csproj index 79c02dbae..79a3bdd17 100644 --- a/src/Validation.ScanAndSign.Core/Validation.ScanAndSign.Core.csproj +++ b/src/Validation.ScanAndSign.Core/Validation.ScanAndSign.Core.csproj @@ -64,7 +64,7 @@ all - 2.52.0 + 2.53.0 0.3.0 diff --git a/tests/NuGet.Services.Revalidate.Tests/Services/RevalidationStarterFacts.cs b/tests/NuGet.Services.Revalidate.Tests/Services/RevalidationStarterFacts.cs index 2b580eb56..4d6bbb195 100644 --- a/tests/NuGet.Services.Revalidate.Tests/Services/RevalidationStarterFacts.cs +++ b/tests/NuGet.Services.Revalidate.Tests/Services/RevalidationStarterFacts.cs @@ -181,7 +181,7 @@ public async Task StartsNextRevalidation() _validationEnqueuer .Setup(e => e.StartValidationAsync(It.IsAny())) - .Callback(m => steps.Add($"Enqueue {m.PackageId} {m.PackageNormalizedVersion}")) + .Callback(m => steps.Add($"Enqueue {m.ProcessValidationSet.PackageId} {m.ProcessValidationSet.PackageNormalizedVersion}")) .Returns(Task.CompletedTask); _packageState @@ -202,9 +202,10 @@ public async Task StartsNextRevalidation() _validationEnqueuer.Verify( e => e.StartValidationAsync(It.Is(m => - m.PackageId == _revalidation1.PackageId && - m.PackageNormalizedVersion == _revalidation1.PackageNormalizedVersion && - m.ValidationTrackingId == _revalidation1.ValidationTrackingId.Value)), + m.Type == PackageValidationMessageType.ProcessValidationSet && + m.ProcessValidationSet.PackageId == _revalidation1.PackageId && + m.ProcessValidationSet.PackageNormalizedVersion == _revalidation1.PackageNormalizedVersion && + m.ProcessValidationSet.ValidationTrackingId == _revalidation1.ValidationTrackingId.Value)), Times.Once); _packageState.Verify( diff --git a/tests/NuGet.Services.Validation.Orchestrator.Tests/SymbolValidationMessageHandlerFacts.cs b/tests/NuGet.Services.Validation.Orchestrator.Tests/SymbolValidationMessageHandlerFacts.cs index 76801e817..79d646a51 100644 --- a/tests/NuGet.Services.Validation.Orchestrator.Tests/SymbolValidationMessageHandlerFacts.cs +++ b/tests/NuGet.Services.Validation.Orchestrator.Tests/SymbolValidationMessageHandlerFacts.cs @@ -20,13 +20,93 @@ public SymbolValidationMessageHandlerStrictFacts() : base(MockBehavior.Strict) { } [Fact] - public async Task WaitsForPackageAvailabilityInGalleryDB() + public async Task WaitsForValidationSetAvailabilityInValidationDBWithCheckValidator() { - var messageData = new PackageValidationMessageData("packageId", "1.2.3", Guid.NewGuid(), ValidatingType.SymbolPackage); + var messageData = PackageValidationMessageData.NewCheckValidator(Guid.NewGuid()); + var validationConfiguration = new ValidationConfiguration(); + + ValidationSetProviderMock + .Setup(ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId)) + .ReturnsAsync((PackageValidationSet)null) + .Verifiable(); + + var handler = CreateHandler(); + + var result = await handler.HandleAsync(messageData); + + ValidationSetProviderMock.Verify( + ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId), + Times.Once); + + Assert.False(result, "The handler should not have succeeded."); + } + + [Fact] + public async Task RejectsNonSymbolPackageValidationSetWithCheckValidator() + { + var messageData = PackageValidationMessageData.NewCheckValidator(Guid.NewGuid()); + var validationConfiguration = new ValidationConfiguration(); + var validationSet = new PackageValidationSet { PackageKey = 42, ValidatingType = ValidatingType.Package }; + + ValidationSetProviderMock + .Setup(ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId)) + .ReturnsAsync(validationSet) + .Verifiable(); + + var handler = CreateHandler(); + + var result = await handler.HandleAsync(messageData); + + ValidationSetProviderMock.Verify( + ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId), + Times.Once); + + Assert.False(result, "The handler should not have succeeded."); + } + + [Fact] + public async Task WaitsForPackageAvailabilityInGalleryDBWithCheckValidator() + { + var messageData = PackageValidationMessageData.NewCheckValidator(Guid.NewGuid()); + var validationConfiguration = new ValidationConfiguration(); + var validationSet = new PackageValidationSet { PackageKey = 42, ValidatingType = ValidatingType.SymbolPackage }; + + ValidationSetProviderMock + .Setup(ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId)) + .ReturnsAsync(validationSet) + .Verifiable(); + CoreSymbolPackageServiceMock + .Setup(ps => ps.FindPackageByKey(validationSet.PackageKey)) + .Returns(null) + .Verifiable(); + + var handler = CreateHandler(); + + var result = await handler.HandleAsync(messageData); + + ValidationSetProviderMock.Verify( + ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId), + Times.Once); + CoreSymbolPackageServiceMock.Verify( + ps => ps.FindPackageByKey(validationSet.PackageKey), + Times.Once); + + Assert.False(result, "The handler should not have succeeded."); + } + + [Fact] + public async Task WaitsForPackageAvailabilityInGalleryDBWithProcessValidationSet() + { + var messageData = PackageValidationMessageData.NewProcessValidationSet( + "packageId", + "1.2.3", + Guid.NewGuid(), + ValidatingType.SymbolPackage, + entityKey: null); var validationConfiguration = new ValidationConfiguration(); CoreSymbolPackageServiceMock - .Setup(ps => ps.FindPackageByIdAndVersionStrict(messageData.PackageId, messageData.PackageVersion)) + .Setup(ps => ps.FindPackageByIdAndVersionStrict(messageData.ProcessValidationSet.PackageId, messageData.ProcessValidationSet.PackageVersion)) .Returns(null) .Verifiable(); @@ -34,14 +114,21 @@ public async Task WaitsForPackageAvailabilityInGalleryDB() await handler.HandleAsync(messageData); - CoreSymbolPackageServiceMock.Verify(ps => ps.FindPackageByIdAndVersionStrict(messageData.PackageId, messageData.PackageVersion), Times.Once()); + CoreSymbolPackageServiceMock.Verify( + ps => ps.FindPackageByIdAndVersionStrict(messageData.ProcessValidationSet.PackageId, messageData.ProcessValidationSet.PackageVersion), + Times.Once); } [Fact] public async Task DropsMessageAfterMissingPackageRetryCountIsReached() { var validationTrackingId = Guid.NewGuid(); - var messageData = new PackageValidationMessageData("packageId", "1.2.3", validationTrackingId, ValidatingType.SymbolPackage); + var messageData = PackageValidationMessageData.NewProcessValidationSet( + "packageId", + "1.2.3", + validationTrackingId, + ValidatingType.SymbolPackage, + entityKey: null); CoreSymbolPackageServiceMock .Setup(ps => ps.FindPackageByIdAndVersionStrict("packageId", "1.2.3")) @@ -78,18 +165,25 @@ private PackageValidationMessageData OverrideDeliveryCount( [Fact] public async Task DropsMessageOnDuplicateValidationRequest() { - var messageData = new PackageValidationMessageData("packageId", "1.2.3", Guid.NewGuid(), ValidatingType.SymbolPackage); + 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.PackageId, messageData.PackageVersion)) + .Setup(ps => ps.FindPackageByIdAndVersionStrict( + messageData.ProcessValidationSet.PackageId, + messageData.ProcessValidationSet.PackageVersion)) .Returns(symbolPackageValidatingEntity) .Verifiable(); ValidationSetProviderMock - .Setup(vsp => vsp.TryGetOrCreateValidationSetAsync(messageData, symbolPackageValidatingEntity)) + .Setup(vsp => vsp.TryGetOrCreateValidationSetAsync(messageData.ProcessValidationSet, symbolPackageValidatingEntity)) .ReturnsAsync((PackageValidationSet)null) .Verifiable(); @@ -98,10 +192,16 @@ public async Task DropsMessageOnDuplicateValidationRequest() var result = await handler.HandleAsync(messageData); Assert.True(result); - CoreSymbolPackageServiceMock - .Verify(ps => ps.FindPackageByIdAndVersionStrict(messageData.PackageId, messageData.PackageVersion), Times.Once()); - ValidationSetProviderMock - .Verify(vsp => vsp.TryGetOrCreateValidationSetAsync(messageData, symbolPackageValidatingEntity), Times.Once()); + CoreSymbolPackageServiceMock.Verify( + ps => ps.FindPackageByIdAndVersionStrict( + messageData.ProcessValidationSet.PackageId, + messageData.ProcessValidationSet.PackageVersion), + Times.Once); + ValidationSetProviderMock.Verify( + vsp => vsp.TryGetOrCreateValidationSetAsync( + messageData.ProcessValidationSet, + symbolPackageValidatingEntity), + Times.Once); } private class MessageWithCustomDeliveryCount : IBrokeredMessage @@ -136,35 +236,78 @@ public MessageWithCustomDeliveryCount(IBrokeredMessage inner, int deliveryCount) public class SymbolValidationMessageHandlerLooseFacts : SymbolValidationMessageHandlerFactsBase { protected SymbolPackage SymbolPackage { get; } - protected PackageValidationMessageData MessageData { get; } + protected PackageValidationMessageData ProcessValidationSetData { get; } + protected PackageValidationMessageData CheckValidatorData { get; } protected PackageValidationSet ValidationSet { get; } protected SymbolPackageValidatingEntity SymbolPackageValidatingEntity { get; } public SymbolValidationMessageHandlerLooseFacts() : base(MockBehavior.Loose) { - SymbolPackage = new SymbolPackage() { Package = new Package() }; - MessageData = new PackageValidationMessageData("packageId", "1.2.3", Guid.NewGuid(), ValidatingType.SymbolPackage); - ValidationSet = new PackageValidationSet(); + SymbolPackage = new SymbolPackage() { Package = new Package(), Key = 42 }; + ProcessValidationSetData = PackageValidationMessageData.NewProcessValidationSet( + "packageId", + "1.2.3", + Guid.NewGuid(), + ValidatingType.SymbolPackage, + entityKey: null); + CheckValidatorData = PackageValidationMessageData.NewCheckValidator(Guid.NewGuid()); + ValidationSet = new PackageValidationSet { ValidatingType = ValidatingType.SymbolPackage, PackageKey = SymbolPackage.Key }; SymbolPackageValidatingEntity = new SymbolPackageValidatingEntity(SymbolPackage); CoreSymbolPackageServiceMock - .Setup(ps => ps.FindPackageByIdAndVersionStrict(MessageData.PackageId, MessageData.PackageVersion)) + .Setup(ps => ps.FindPackageByIdAndVersionStrict( + ProcessValidationSetData.ProcessValidationSet.PackageId, + ProcessValidationSetData.ProcessValidationSet.PackageVersion)) + .Returns(SymbolPackageValidatingEntity); + CoreSymbolPackageServiceMock + .Setup(ps => ps.FindPackageByKey(SymbolPackage.Key)) .Returns(SymbolPackageValidatingEntity); ValidationSetProviderMock - .Setup(vsp => vsp.TryGetOrCreateValidationSetAsync(MessageData, SymbolPackageValidatingEntity)) + .Setup(vsp => vsp.TryGetOrCreateValidationSetAsync( + ProcessValidationSetData.ProcessValidationSet, + SymbolPackageValidatingEntity)) + .ReturnsAsync(ValidationSet); + ValidationSetProviderMock + .Setup(vsp => vsp.TryGetParentValidationSetAsync(CheckValidatorData.CheckValidator.ValidationId)) .ReturnsAsync(ValidationSet); } [Fact] - public async Task MakesSureValidationSetExists() + public async Task MakesSureValidationSetExistsForProcessValidationSet() { var handler = CreateHandler(); - await handler.HandleAsync(MessageData); + await handler.HandleAsync(ProcessValidationSetData); - ValidationSetProviderMock - .Verify(vsp => vsp.TryGetOrCreateValidationSetAsync(MessageData, SymbolPackageValidatingEntity)); + ValidationSetProviderMock.Verify( + vsp => vsp.TryGetOrCreateValidationSetAsync( + ProcessValidationSetData.ProcessValidationSet, + SymbolPackageValidatingEntity)); + } + + [Fact] + public async Task CallsProcessValidationsForProcessValidationSet() + { + var handler = CreateHandler(); + await handler.HandleAsync(ProcessValidationSetData); + + ValidationSetProcessorMock + .Verify(vsp => vsp.ProcessValidationsAsync(ValidationSet), Times.Once()); + } + + [Fact] + public async Task CallsProcessValidationOutcomeForProcessValidationSet() + { + var handler = CreateHandler(); + await handler.HandleAsync(ProcessValidationSetData); + + ValidationOutcomeProcessorMock + .Verify(vop => vop.ProcessValidationOutcomeAsync( + ValidationSet, + SymbolPackageValidatingEntity, + It.IsAny(), + true)); } [Fact] @@ -173,7 +316,7 @@ public async Task SkipsCompletedValidationSets() ValidationSet.ValidationSetStatus = ValidationSetStatus.Completed; var handler = CreateHandler(); - var output = await handler.HandleAsync(MessageData); + var output = await handler.HandleAsync(ProcessValidationSetData); Assert.True(output, "The message should have been successfully processed."); @@ -184,28 +327,33 @@ public async Task SkipsCompletedValidationSets() vop => vop.ProcessValidationOutcomeAsync( It.IsAny(), It.IsAny>(), - It.IsAny()), + It.IsAny(), + It.IsAny()), Times.Never); } [Fact] - public async Task CallsProcessValidations() + public async Task CallsProcessValidationsForCheckValidator() { var handler = CreateHandler(); - await handler.HandleAsync(MessageData); + await handler.HandleAsync(CheckValidatorData); ValidationSetProcessorMock .Verify(vsp => vsp.ProcessValidationsAsync(ValidationSet), Times.Once()); } [Fact] - public async Task CallsProcessValidationOutcome() + public async Task CallsProcessValidationOutcomeForCheckValidator() { var handler = CreateHandler(); - await handler.HandleAsync(MessageData); + await handler.HandleAsync(CheckValidatorData); ValidationOutcomeProcessorMock - .Verify(vop => vop.ProcessValidationOutcomeAsync(ValidationSet, SymbolPackageValidatingEntity, It.IsAny())); + .Verify(vop => vop.ProcessValidationOutcomeAsync( + ValidationSet, + SymbolPackageValidatingEntity, + It.IsAny(), + false)); } } diff --git a/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationMessageHandlerFacts.cs b/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationMessageHandlerFacts.cs index 87f540da3..b6b966f97 100644 --- a/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationMessageHandlerFacts.cs +++ b/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationMessageHandlerFacts.cs @@ -22,13 +22,95 @@ public ValidationMessageHandlerStrictFacts() } [Fact] - public async Task WaitsForPackageAvailabilityInGalleryDB() + public async Task WaitsForValidationSetAvailabilityInValidationDBWithCheckValidator() { - var messageData = new PackageValidationMessageData("packageId", "1.2.3", Guid.NewGuid()); + var messageData = PackageValidationMessageData.NewCheckValidator(Guid.NewGuid()); + var validationConfiguration = new ValidationConfiguration(); + + ValidationSetProviderMock + .Setup(ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId)) + .ReturnsAsync((PackageValidationSet)null) + .Verifiable(); + + var handler = CreateHandler(); + + var result = await handler.HandleAsync(messageData); + + ValidationSetProviderMock.Verify( + ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId), + Times.Once); + + Assert.False(result, "The handler should not have succeeded."); + } + + [Fact] + public async Task RejectsNonPackageValidationSetWithCheckValidator() + { + var messageData = PackageValidationMessageData.NewCheckValidator(Guid.NewGuid()); + var validationConfiguration = new ValidationConfiguration(); + var validationSet = new PackageValidationSet { PackageKey = 42, ValidatingType = ValidatingType.SymbolPackage }; + + ValidationSetProviderMock + .Setup(ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId)) + .ReturnsAsync(validationSet) + .Verifiable(); + + var handler = CreateHandler(); + + var result = await handler.HandleAsync(messageData); + + ValidationSetProviderMock.Verify( + ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId), + Times.Once); + + Assert.False(result, "The handler should not have succeeded."); + } + + [Fact] + public async Task WaitsForPackageAvailabilityInGalleryDBWithCheckValidator() + { + var messageData = PackageValidationMessageData.NewCheckValidator(Guid.NewGuid()); + var validationConfiguration = new ValidationConfiguration(); + var validationSet = new PackageValidationSet { PackageKey = 42, ValidatingType = ValidatingType.Package }; + + ValidationSetProviderMock + .Setup(ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId)) + .ReturnsAsync(validationSet) + .Verifiable(); + CorePackageServiceMock + .Setup(ps => ps.FindPackageByKey(validationSet.PackageKey)) + .Returns(null) + .Verifiable(); + + var handler = CreateHandler(); + + var result = await handler.HandleAsync(messageData); + + ValidationSetProviderMock.Verify( + ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId), + Times.Once); + CorePackageServiceMock.Verify( + ps => ps.FindPackageByKey(validationSet.PackageKey), + Times.Once); + + Assert.False(result, "The handler should not have succeeded."); + } + + [Fact] + 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.PackageId, messageData.PackageVersion)) + .Setup(ps => ps.FindPackageByIdAndVersionStrict( + messageData.ProcessValidationSet.PackageId, + messageData.ProcessValidationSet.PackageVersion)) .Returns(null) .Verifiable(); @@ -36,14 +118,23 @@ public async Task WaitsForPackageAvailabilityInGalleryDB() await handler.HandleAsync(messageData); - CorePackageServiceMock.Verify(ps => ps.FindPackageByIdAndVersionStrict(messageData.PackageId, messageData.PackageVersion), Times.Once()); + CorePackageServiceMock.Verify( + ps => ps.FindPackageByIdAndVersionStrict( + messageData.ProcessValidationSet.PackageId, + messageData.ProcessValidationSet.PackageVersion), + Times.Once); } [Fact] public async Task DropsMessageAfterMissingPackageRetryCountIsReached() { var validationTrackingId = Guid.NewGuid(); - var messageData = new PackageValidationMessageData("packageId", "1.2.3", validationTrackingId); + var messageData = PackageValidationMessageData.NewProcessValidationSet( + "packageId", + "1.2.3", + validationTrackingId, + ValidatingType.Package, + entityKey: null); CorePackageServiceMock .Setup(ps => ps.FindPackageByIdAndVersionStrict("packageId", "1.2.3")) @@ -80,18 +171,27 @@ private PackageValidationMessageData OverrideDeliveryCount( [Fact] public async Task DropsMessageOnDuplicateValidationRequest() { - var messageData = new PackageValidationMessageData("packageId", "1.2.3", Guid.NewGuid()); + var messageData = PackageValidationMessageData.NewProcessValidationSet( + "packageId", + "1.2.3", + Guid.NewGuid(), + ValidatingType.Package, + entityKey: null); var validationConfiguration = new ValidationConfiguration(); var package = new Package(); var packageValidatingEntity = new PackageValidatingEntity(package); CorePackageServiceMock - .Setup(ps => ps.FindPackageByIdAndVersionStrict(messageData.PackageId, messageData.PackageVersion)) + .Setup(ps => ps.FindPackageByIdAndVersionStrict( + messageData.ProcessValidationSet.PackageId, + messageData.ProcessValidationSet.PackageVersion)) .Returns(packageValidatingEntity) .Verifiable(); ValidationSetProviderMock - .Setup(vsp => vsp.TryGetOrCreateValidationSetAsync(messageData, packageValidatingEntity)) + .Setup(vsp => vsp.TryGetOrCreateValidationSetAsync( + messageData.ProcessValidationSet, + packageValidatingEntity)) .ReturnsAsync((PackageValidationSet)null) .Verifiable(); @@ -100,22 +200,35 @@ public async Task DropsMessageOnDuplicateValidationRequest() var result = await handler.HandleAsync(messageData); Assert.True(result); - CorePackageServiceMock - .Verify(ps => ps.FindPackageByIdAndVersionStrict(messageData.PackageId, messageData.PackageVersion), Times.Once()); - ValidationSetProviderMock - .Verify(vsp => vsp.TryGetOrCreateValidationSetAsync(messageData, packageValidatingEntity), Times.Once()); + CorePackageServiceMock.Verify( + ps => ps.FindPackageByIdAndVersionStrict( + messageData.ProcessValidationSet.PackageId, + messageData.ProcessValidationSet.PackageVersion), + Times.Once); + ValidationSetProviderMock.Verify( + vsp => vsp.TryGetOrCreateValidationSetAsync( + messageData.ProcessValidationSet, + packageValidatingEntity), + Times.Once); } [Fact] - public async Task DropsMessageIfPackageIsSoftDeleted() + public async Task DropsMessageIfPackageIsSoftDeletedForProcessValidationSet() { - var messageData = new PackageValidationMessageData("packageId", "1.2.3", Guid.NewGuid()); + 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.PackageId, messageData.PackageVersion)) + .Setup(ps => ps.FindPackageByIdAndVersionStrict( + messageData.ProcessValidationSet.PackageId, + messageData.ProcessValidationSet.PackageVersion)) .Returns(packageValidatingEntity); var handler = CreateHandler(); @@ -123,8 +236,41 @@ public async Task DropsMessageIfPackageIsSoftDeleted() var result = await handler.HandleAsync(messageData); Assert.True(result); + CorePackageServiceMock.Verify( + ps => ps.FindPackageByIdAndVersionStrict( + messageData.ProcessValidationSet.PackageId, + messageData.ProcessValidationSet.PackageVersion), + Times.Once); + } + + [Fact] + public async Task DropsMessageIfPackageIsSoftDeletedForCheckValidator() + { + var messageData = PackageValidationMessageData.NewCheckValidator(Guid.NewGuid()); + var validationConfiguration = new ValidationConfiguration(); + var package = new Package { Key = 42, PackageStatusKey = PackageStatus.Deleted }; + var packageValidatingEntity = new PackageValidatingEntity(package); + var validationSet = new PackageValidationSet { PackageKey = package.Key, ValidatingType = ValidatingType.Package }; + + ValidationSetProviderMock + .Setup(ps => ps.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId)) + .ReturnsAsync(validationSet) + .Verifiable(); CorePackageServiceMock - .Verify(ps => ps.FindPackageByIdAndVersionStrict(messageData.PackageId, messageData.PackageVersion), Times.Once); + .Setup(ps => ps.FindPackageByKey(package.Key)) + .Returns(packageValidatingEntity); + + var handler = CreateHandler(); + + var result = await handler.HandleAsync(messageData); + + Assert.True(result); + ValidationSetProviderMock.Verify( + vsp => vsp.TryGetParentValidationSetAsync(messageData.CheckValidator.ValidationId), + Times.Once); + CorePackageServiceMock.Verify( + ps => ps.FindPackageByKey(package.Key), + Times.Once); } private class MessageWithCustomDeliveryCount : IBrokeredMessage @@ -159,24 +305,41 @@ public MessageWithCustomDeliveryCount(IBrokeredMessage inner, int deliveryCount) public class ValidationMessageHandlerLooseFacts : ValidationMessageHandlerFactsBase { protected Package Package { get; } - protected PackageValidationMessageData MessageData { get; } + protected PackageValidationMessageData ProcessValidationSetData { get; } + protected PackageValidationMessageData CheckValidatorData { get; } protected PackageValidationSet ValidationSet { get; } protected PackageValidatingEntity PackageValidatingEntity { get; } public ValidationMessageHandlerLooseFacts() : base(MockBehavior.Loose) { - Package = new Package(); - MessageData = new PackageValidationMessageData("packageId", "1.2.3", Guid.NewGuid()); - ValidationSet = new PackageValidationSet(); + Package = new Package { Key = 42 }; + ProcessValidationSetData = PackageValidationMessageData.NewProcessValidationSet( + "packageId", + "1.2.3", + Guid.NewGuid(), + ValidatingType.Package, + entityKey: null); + CheckValidatorData = PackageValidationMessageData.NewCheckValidator(Guid.NewGuid()); + ValidationSet = new PackageValidationSet { PackageKey = Package.Key, ValidatingType = ValidatingType.Package }; PackageValidatingEntity = new PackageValidatingEntity(Package); CorePackageServiceMock - .Setup(ps => ps.FindPackageByIdAndVersionStrict(MessageData.PackageId, MessageData.PackageVersion)) + .Setup(ps => ps.FindPackageByIdAndVersionStrict( + ProcessValidationSetData.ProcessValidationSet.PackageId, + ProcessValidationSetData.ProcessValidationSet.PackageVersion)) + .Returns(PackageValidatingEntity); + CorePackageServiceMock + .Setup(ps => ps.FindPackageByKey(Package.Key)) .Returns(PackageValidatingEntity); ValidationSetProviderMock - .Setup(vsp => vsp.TryGetOrCreateValidationSetAsync(MessageData, PackageValidatingEntity)) + .Setup(vsp => vsp.TryGetOrCreateValidationSetAsync( + ProcessValidationSetData.ProcessValidationSet, + PackageValidatingEntity)) + .ReturnsAsync(ValidationSet); + ValidationSetProviderMock + .Setup(vsp => vsp.TryGetParentValidationSetAsync(CheckValidatorData.CheckValidator.ValidationId)) .ReturnsAsync(ValidationSet); } @@ -184,10 +347,35 @@ public ValidationMessageHandlerLooseFacts() public async Task MakesSureValidationSetExists() { var handler = CreateHandler(); - await handler.HandleAsync(MessageData); + await handler.HandleAsync(ProcessValidationSetData); - ValidationSetProviderMock - .Verify(vsp => vsp.TryGetOrCreateValidationSetAsync(MessageData, PackageValidatingEntity)); + ValidationSetProviderMock.Verify(vsp => vsp.TryGetOrCreateValidationSetAsync( + ProcessValidationSetData.ProcessValidationSet, + PackageValidatingEntity)); + } + + [Fact] + public async Task CallsProcessValidationsForProcessValidationSet() + { + var handler = CreateHandler(); + await handler.HandleAsync(ProcessValidationSetData); + + ValidationSetProcessorMock + .Verify(vsp => vsp.ProcessValidationsAsync(ValidationSet), Times.Once()); + } + + [Fact] + public async Task CallsProcessValidationOutcomeForProcessValidationSet() + { + var handler = CreateHandler(); + await handler.HandleAsync(ProcessValidationSetData); + + ValidationOutcomeProcessorMock.Verify( + vop => vop.ProcessValidationOutcomeAsync( + ValidationSet, + PackageValidatingEntity, + It.IsAny(), + true)); } [Fact] @@ -196,7 +384,7 @@ public async Task SkipsCompletedValidationSets() ValidationSet.ValidationSetStatus = ValidationSetStatus.Completed; var handler = CreateHandler(); - var output = await handler.HandleAsync(MessageData); + var output = await handler.HandleAsync(ProcessValidationSetData); Assert.True(output, "The message should have been successfully processed."); @@ -207,28 +395,33 @@ public async Task SkipsCompletedValidationSets() vop => vop.ProcessValidationOutcomeAsync( It.IsAny(), It.IsAny>(), - It.IsAny()), + It.IsAny(), + It.IsAny()), Times.Never); } [Fact] - public async Task CallsProcessValidations() + public async Task CallsProcessValidationsForCheckValidator() { var handler = CreateHandler(); - await handler.HandleAsync(MessageData); + await handler.HandleAsync(CheckValidatorData); ValidationSetProcessorMock .Verify(vsp => vsp.ProcessValidationsAsync(ValidationSet), Times.Once()); } [Fact] - public async Task CallsProcessValidationOutcome() + public async Task CallsProcessValidationOutcomeForCheckValidator() { var handler = CreateHandler(); - await handler.HandleAsync(MessageData); + await handler.HandleAsync(CheckValidatorData); - ValidationOutcomeProcessorMock - .Verify(vop => vop.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, It.IsAny())); + ValidationOutcomeProcessorMock.Verify( + vop => vop.ProcessValidationOutcomeAsync( + ValidationSet, + PackageValidatingEntity, + It.IsAny(), + false)); } } diff --git a/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationOutcomeProcessorFacts.cs b/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationOutcomeProcessorFacts.cs index d735b422e..f9622416f 100644 --- a/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationOutcomeProcessorFacts.cs +++ b/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationOutcomeProcessorFacts.cs @@ -24,7 +24,7 @@ public async Task ProcessesFailedValidationAccordingToFailureBehavior(Validation AddValidation("validation1", ValidationStatus.Failed, failureBehavior); var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); PackageStateProcessorMock.Verify( x => x.SetStatusAsync(PackageValidatingEntity, ValidationSet, expectedPackageStatus), @@ -48,7 +48,7 @@ public async Task SendsFailureEmailOnFailedValidation(ValidationIssueCode[] issu .ToList(); var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); MessageServiceMock .Verify(ms => ms.SendValidationFailedMessageAsync(Package, ValidationSet), Times.Once()); @@ -76,7 +76,7 @@ public async Task TracksTimedOutValidators() Configuration.ValidationMessageRecheckPeriod = TimeSpan.FromMinutes(postponeMinutes); var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); TelemetryServiceMock .Verify(t => t.TrackValidatorTimeout(ValidationSet.PackageId, ValidationSet.PackageNormalizedVersion, ValidationSet.ValidationTrackingId, "IncompleteButTimedOut")); @@ -104,7 +104,7 @@ public async Task DoesNotReEnqueueProcessingIfValidationSetTimesOut() .Returns(Task.FromResult(0)); var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); TelemetryServiceMock .Verify(t => t.TrackValidationSetTimeout(Package.PackageRegistration.Id, Package.NormalizedVersion, ValidationSet.ValidationTrackingId)); @@ -147,7 +147,7 @@ public async Task SendsValidatingTooLongMessageOnlyIfPackageIsInValidatingState( // Process the outcome once - the "too long to validate" message should be sent. var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); if (shouldSend) { @@ -177,7 +177,7 @@ public async Task SendsValidatingTooLongMessageOnlyIfPackageIsInValidatingState( ValidationEnqueuerMock.ResetCalls(); // Process the outcome again - the "too long to validate" message should NOT be sent. - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); TelemetryServiceMock .Verify(t => t.TrackSentValidationTakingTooLongMessage(Package.PackageRegistration.Id, Package.NormalizedVersion, ValidationSet.ValidationTrackingId), Times.Never); @@ -214,7 +214,7 @@ public async Task DoesNotSendValidatingTooLongMessageOnRevalidations() // Process the outcome once - the "too long to validate" message should NOT be sent. var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); TelemetryServiceMock .Verify(t => t.TrackSentValidationTakingTooLongMessage(Package.PackageRegistration.Id, Package.NormalizedVersion, ValidationSet.ValidationTrackingId), Times.Never); @@ -246,7 +246,7 @@ public async Task ReEnqueuesProcessingIfNotAllComplete() var processor = CreateProcessor(); var startTime = DateTimeOffset.Now; - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); ValidationStorageServiceMock .Verify(s => s.UpdateValidationSetAsync(ValidationSet), Times.Once); @@ -263,11 +263,12 @@ public async Task ReEnqueuesProcessingIfNotAllComplete() Times.Never); Assert.NotNull(messageData); - Assert.Equal(ValidationSet.ValidationTrackingId, messageData.ValidationTrackingId); - Assert.Equal(ValidationSet.PackageId, messageData.PackageId); - Assert.Equal(Package.NormalizedVersion, messageData.PackageVersion); - Assert.Equal(ValidationSet.ValidatingType, messageData.ValidatingType); - Assert.Equal(ValidationSet.PackageKey, messageData.EntityKey); + Assert.Equal(PackageValidationMessageType.ProcessValidationSet, messageData.Type); + Assert.Equal(ValidationSet.ValidationTrackingId, messageData.ProcessValidationSet.ValidationTrackingId); + Assert.Equal(ValidationSet.PackageId, messageData.ProcessValidationSet.PackageId); + Assert.Equal(Package.NormalizedVersion, messageData.ProcessValidationSet.PackageVersion); + Assert.Equal(ValidationSet.ValidatingType, messageData.ProcessValidationSet.ValidatingType); + Assert.Equal(ValidationSet.PackageKey, messageData.ProcessValidationSet.EntityKey); Assert.Equal(postponeMinutes, (postponeTill - startTime).TotalMinutes, 0); Assert.Equal(ValidationSetStatus.InProgress, ValidationSet.ValidationSetStatus); } @@ -279,7 +280,7 @@ public async Task DoesNotSendSuccessEmailIfPackageIsAlreadyAvailable() Package.PackageStatusKey = PackageStatus.Available; var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); MessageServiceMock.Verify( x => x.SendPublishedMessageAsync(It.IsAny()), @@ -293,7 +294,7 @@ public async Task MakesPackageAvailableAndSendsEmailUponSuccess() Package.PackageStatusKey = PackageStatus.Validating; var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); PackageStateProcessorMock.Verify( x => x.SetStatusAsync(PackageValidatingEntity, ValidationSet, PackageStatus.Available), @@ -323,7 +324,7 @@ public async Task HasProperOperationOrderWhenTransitioningToAvailable(PackageSta var operations = RecordOperationOrder(); var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); Assert.Equal( new[] @@ -346,7 +347,7 @@ public async Task HasProperOperationOrderWhenAlreadyAvailable() var operations = RecordOperationOrder(); var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); Assert.Equal( new[] @@ -367,7 +368,7 @@ public async Task HasProperOperationOrderWhenTransitioningToFailedValidation() var operations = RecordOperationOrder(); var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); Assert.Equal( new[] @@ -392,7 +393,7 @@ public async Task HasProperOperationOrderWhenTerminalAndValidationFailed(Package var operations = RecordOperationOrder(); var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); Assert.Equal( new[] @@ -431,7 +432,7 @@ public async Task MarksPackageStatusBasedOnValidatorResults( var processor = CreateProcessor(); var before = DateTime.UtcNow; - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); var after = DateTime.UtcNow; if (expectedSetPackageStatusCall) @@ -480,7 +481,7 @@ public async Task TracksSuccessOnAllRequiredValidatorsFinished(bool requiredVali ProcessorStats.AnyRequiredValidationSucceeded = requiredValidationSucceeded; var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); if (expectedCompletionTracking) { @@ -507,7 +508,7 @@ public async Task ContinuesCheckingStatusIfOptionalValidationsAreRunning(bool re Configuration.TimeoutValidationSetAfter = TimeSpan.FromDays(1); var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); ValidationEnqueuerMock .Verify(ve => ve.StartValidationAsync(It.IsAny(), It.IsAny()), Times.Once()); @@ -515,6 +516,26 @@ public async Task ContinuesCheckingStatusIfOptionalValidationsAreRunning(bool re Assert.Equal(ValidationSetStatus.InProgress, ValidationSet.ValidationSetStatus); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task DoesNotScheduleNextCheckIfScheduleNextCheckIfFalse(bool requiredValidationSucceeded) + { + AddValidation("requiredValidation", ValidationStatus.Succeeded, ValidationFailureBehavior.MustSucceed); + AddValidation("optionalValidaiton", ValidationStatus.Incomplete, ValidationFailureBehavior.AllowedToFail); + ProcessorStats.AnyRequiredValidationSucceeded = requiredValidationSucceeded; + ScheduleNextCheck = false; + Configuration.TimeoutValidationSetAfter = TimeSpan.FromDays(1); + + var processor = CreateProcessor(); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); + + ValidationEnqueuerMock.Verify( + ve => ve.StartValidationAsync(It.IsAny(), It.IsAny()), + Times.Never); + Assert.Equal(ValidationSetStatus.InProgress, ValidationSet.ValidationSetStatus); + } + [Theory] [InlineData(true, ValidationStatus.Succeeded)] [InlineData(true, ValidationStatus.Failed)] @@ -528,7 +549,7 @@ public async Task StopsCheckingStatusWhenOptionalValidationsFinish(bool required Configuration.TimeoutValidationSetAfter = TimeSpan.FromDays(1); var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); ValidationEnqueuerMock .Verify(ve => ve.StartValidationAsync(It.IsAny(), It.IsAny()), Times.Never()); @@ -571,7 +592,7 @@ public async Task SendsTooLongNotificationOnlyWhenItConcernsRequiredValidation( .Returns(Task.FromResult(1)); var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); if (expectedNotification) { @@ -592,7 +613,7 @@ public async Task DoesNotTakeDownAvailablePackages() Package.PackageStatusKey = PackageStatus.Available; var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); PackageFileServiceMock.Verify( x => x.DeletePackageForValidationSetAsync(ValidationSet), @@ -646,7 +667,7 @@ public async Task PrefersDbOverConfigurationForDeterminingSuccess( } var processor = CreateProcessor(); - await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats); + await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck); if (expectedStatus != PackageStatus.Validating) { @@ -678,7 +699,7 @@ public async Task PackageStillBecomesAvailableIfPublishedMessageFails() var processor = CreateProcessor(); var thrownException = await Record.ExceptionAsync( - async () => await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats)); + async () => await processor.ProcessValidationOutcomeAsync(ValidationSet, PackageValidatingEntity, ProcessorStats, ScheduleNextCheck)); Assert.NotNull(thrownException); PackageStateProcessorMock.Verify( @@ -710,6 +731,7 @@ public ValidationOutcomeProcessorFacts() PackageStatusKey = PackageStatus.Validating }; Package.PackageRegistration.Packages.Add(Package); + ScheduleNextCheck = true; ValidationSet = new PackageValidationSet(); ValidationSet.PackageValidations = new List(); @@ -752,6 +774,7 @@ protected ValidationOutcomeProcessor CreateProcessor() public Mock TelemetryServiceMock { get; } protected Mock>> LoggerMock { get; } protected ValidationConfiguration Configuration { get; } + protected bool ScheduleNextCheck { get; set; } protected PackageValidationSet ValidationSet { get; } protected Package Package { get; } protected ValidationSetProcessorResult ProcessorStats { get; } diff --git a/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationSetProviderFacts.cs b/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationSetProviderFacts.cs index 74c62ed8c..9d326b40b 100644 --- a/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationSetProviderFacts.cs +++ b/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationSetProviderFacts.cs @@ -25,7 +25,7 @@ public class ValidationSetProviderFacts public string ETag { get; } public Package Package { get; } public PackageValidationSet ValidationSet { get; } - public PackageValidationMessageData PackageValidationMessageData { get; } + public ProcessValidationSetData PackageValidationMessageData { get; } public PackageValidatingEntity PackageValidatingEntity { get; } [Fact] @@ -106,10 +106,12 @@ public async Task CopiesToValidationSetContainerBeforeAddingDbRecord() .ReturnsAsync(1); var provider = CreateProvider(); - var packageValidationMessageData = new PackageValidationMessageData( + var packageValidationMessageData = new ProcessValidationSetData( Package.PackageRegistration.Id, Package.NormalizedVersion, - validationTrackingId); + validationTrackingId, + ValidatingType.Package, + Package.Key); await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, new PackageValidatingEntity(Package)); Assert.Equal(new[] @@ -156,10 +158,12 @@ public async Task DoesNotBackUpThePackageWhenThereAreNoValidators() var provider = CreateProvider(); - var packageValidationMessageData = new PackageValidationMessageData( + var packageValidationMessageData = new ProcessValidationSetData( Package.PackageRegistration.Id, Package.NormalizedVersion, - validationTrackingId); + validationTrackingId, + ValidatingType.Package, + Package.Key); var actual = await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, PackageValidatingEntity); PackageFileServiceMock.Verify( @@ -207,10 +211,12 @@ public async Task CopiesPackageFromPackagesContainerWhenAvailable() var provider = CreateProvider(); - var packageValidationMessageData = new PackageValidationMessageData( + var packageValidationMessageData = new ProcessValidationSetData( Package.PackageRegistration.Id, Package.NormalizedVersion, - validationTrackingId); + validationTrackingId, + ValidatingType.Package, + Package.Key); var actual = await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, PackageValidatingEntity); PackageFileServiceMock.Verify(x => x.CopyPackageFileForValidationSetAsync(createdSet), Times.Once); @@ -262,10 +268,12 @@ public async Task CopiesPackageFromValidationContainerWhenNotAvailable(PackageSt var provider = CreateProvider(); - var packageValidationMessageData = new PackageValidationMessageData( + var packageValidationMessageData = new ProcessValidationSetData( Package.PackageRegistration.Id, Package.NormalizedVersion, - validationTrackingId); + validationTrackingId, + ValidatingType.Package, + Package.Key); var actual = await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, PackageValidatingEntity); PackageFileServiceMock.Verify(x => x.CopyPackageFileForValidationSetAsync(It.IsAny()), Times.Never); @@ -344,10 +352,12 @@ public async Task ProperlyConstructsValidationSet() TelemetryServiceMock.Object, LoggerMock.Object); - var packageValidationMessageData = new PackageValidationMessageData( + var packageValidationMessageData = new ProcessValidationSetData( Package.PackageRegistration.Id, Package.NormalizedVersion, - validationTrackingId); + validationTrackingId, + ValidatingType.Package, + Package.Key); var returnedSet = await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, PackageValidatingEntity); var endOfCallTimestamp = DateTime.UtcNow; @@ -433,10 +443,12 @@ public async Task DoesNotCreateValidationsWhenShouldStartFalse() TelemetryServiceMock.Object, LoggerMock.Object); - var packageValidationMessageData = new PackageValidationMessageData( + var packageValidationMessageData = new ProcessValidationSetData( Package.PackageRegistration.Id, Package.NormalizedVersion, - validationTrackingId); + validationTrackingId, + ValidatingType.Package, + Package.Key); var returnedSet = await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, PackageValidatingEntity); var endOfCallTimestamp = DateTime.UtcNow; @@ -508,10 +520,12 @@ public async Task DoesNotEmitTelemetryIfMultipleValidationSetsExist() TelemetryServiceMock.Object, LoggerMock.Object); - var packageValidationMessageData = new PackageValidationMessageData( + var packageValidationMessageData = new ProcessValidationSetData( Package.PackageRegistration.Id, Package.NormalizedVersion, - validationTrackingId); + validationTrackingId, + ValidatingType.Package, + Package.Key); var returnedSet = await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, PackageValidatingEntity); @@ -527,7 +541,12 @@ public async Task DoesNotEmitTelemetryIfMultipleValidationSetsExist() public async Task GetOrCreateValidationSetAsyncDoesNotCreateDuplicateValidationSet() { Guid validationTrackingId = Guid.NewGuid(); - var message = new PackageValidationMessageData(PackageValidationMessageData.PackageId, PackageValidationMessageData.PackageVersion, validationTrackingId); + var message = new ProcessValidationSetData( + PackageValidationMessageData.PackageId, + PackageValidationMessageData.PackageVersion, + validationTrackingId, + ValidatingType.Package, + PackageValidationMessageData.EntityKey); ValidationStorageMock .Setup(vs => vs.GetValidationSetAsync(validationTrackingId)) @@ -611,10 +630,12 @@ public ValidationSetProviderFacts() ValidationTrackingId = Guid.NewGuid(), }; - PackageValidationMessageData = new PackageValidationMessageData( + PackageValidationMessageData = new ProcessValidationSetData( Package.PackageRegistration.Id, Package.NormalizedVersion, - ValidationSet.ValidationTrackingId); + ValidationSet.ValidationTrackingId, + ValidatingType.Package, + Package.Key); PackageValidatingEntity = new PackageValidatingEntity(Package); } diff --git a/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationStorageServiceFacts.cs b/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationStorageServiceFacts.cs index 6c54f487e..e1b86d8f2 100644 --- a/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationStorageServiceFacts.cs +++ b/tests/NuGet.Services.Validation.Orchestrator.Tests/ValidationStorageServiceFacts.cs @@ -120,6 +120,37 @@ public async Task SetsStartedProperty() } } + public class TryGetParentValidationSetAsync : Facts + { + public TryGetParentValidationSetAsync(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public async Task ReturnsNullWhenValidationIdDoesNotMatch() + { + var differentValidationId = Guid.Parse("ca9be0e6-a9e1-49ae-ba35-53c4ee1e45fa"); + _packageValidation.PackageValidationSet = new PackageValidationSet(); + _entitiesContext.Object.PackageValidations.Add(_packageValidation); + + var output = await _target.TryGetParentValidationSetAsync(differentValidationId); + + Assert.Null(output); + } + + [Fact] + public async Task ReturnsValidationSetWhenValidationIdMatches() + { + var packageValidationSet = new PackageValidationSet(); + _packageValidation.PackageValidationSet = packageValidationSet; + _entitiesContext.Object.PackageValidations.Add(_packageValidation); + + var output = await _target.TryGetParentValidationSetAsync(_packageValidation.Key); + + Assert.Same(packageValidationSet, output); + } + } + public class GetValidationSetCountAsync : Facts { public GetValidationSetCountAsync(ITestOutputHelper output) : base(output) @@ -463,6 +494,7 @@ public Facts(ITestOutputHelper output) _validatorType = "ExampleValidator"; _packageValidation = new PackageValidation { + Key = Guid.Parse("dc10bf5a-0557-459c-b33f-ea6738b8a044"), Type = _validatorType, ValidationStatus = ValidationStatus.Incomplete, Started = new DateTime(2017, 1, 1, 8, 30, 0, DateTimeKind.Utc), @@ -482,6 +514,9 @@ public Facts(ITestOutputHelper output) _entitiesContext .Setup(x => x.PackageValidationSets) .Returns(DbSetMockFactory.Create()); + _entitiesContext + .Setup(x => x.PackageValidations) + .Returns(DbSetMockFactory.Create()); _packageFileService = new Mock();