Example #1
0
        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));
        }
Example #4
0
        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);
        }
Example #6
0
            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);
            }
        }
Example #10
0
        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);
        }