/// <summary>
        /// Checks that the current batch of catalog entries contains the entry that was created from the current state of the V2 feed.
        /// </summary>
        protected virtual async Task <bool> ShouldRunAsync(ValidationContext context)
        {
            var timestampV2 = await context.GetTimestampMetadataV2Async();

            var timestampCatalog = await PackageTimestampMetadata.FromCatalogEntries(context.Client, context.Entries);

            if (!timestampV2.Last.HasValue)
            {
                throw new TimestampComparisonException(timestampV2, timestampCatalog,
                                                       "Cannot get timestamp data for package from the V2 feed!");
            }

            if (!timestampCatalog.Last.HasValue)
            {
                throw new TimestampComparisonException(timestampV2, timestampCatalog,
                                                       "Cannot get timestamp data for package from the catalog!");
            }

            if (timestampCatalog.Last > timestampV2.Last)
            {
                throw new TimestampComparisonException(timestampV2, timestampCatalog,
                                                       "The timestamp in the catalog is newer than the timestamp in the feed! This should never happen because all data flows from the feed into the catalog!");
            }

            // If the timestamp metadata in the catalog is LESS than that of the feed, we must not be looking at the latest entry that corresponds with this package, so skip the test for now.
            // If the timestamp metadata in the catalog is EQUAL to that of the feed, we are looking at the latest catalog entry that corresponds with this package, so run the test.
            return(timestampCatalog.Last == timestampV2.Last);
        }
예제 #2
0
        public TimestampComparisonException(PackageTimestampMetadata timestampDatabase, PackageTimestampMetadata timestampCatalog, string message)
            : base(message)
        {
            TimestampDatabase = timestampDatabase;
            TimestampCatalog  = timestampCatalog;

            Data.Add(nameof(TimestampDatabase), JsonConvert.SerializeObject(TimestampDatabase));
            Data.Add(nameof(TimestampCatalog), JsonConvert.SerializeObject(TimestampCatalog));
        }
예제 #3
0
        /// <summary>
        /// Queries the gallery database for the package specified by the <see cref="ValidationContext"/> and returns a <see cref="PackageTimestampMetadata"/>.
        /// If the package is missing from the repository, returns the package's deletion audit record timestamp.
        /// </summary>
        public async Task <PackageTimestampMetadata> GetAsync(ValidationContext context)
        {
            var feedPackageDetails = await _galleryDatabase.GetPackageOrNull(
                context.Package.Id,
                context.Package.Version.ToNormalizedString());

            if (feedPackageDetails != null)
            {
                return(PackageTimestampMetadata.CreateForExistingPackage(
                           feedPackageDetails.CreatedDate,
                           feedPackageDetails.LastEditedDate));
            }

            DateTime?deleted = null;

            if (context.DeletionAuditEntries.Any())
            {
                deleted = context.DeletionAuditEntries.Max(entry => entry.TimestampUtc);
            }

            return(PackageTimestampMetadata.CreateForMissingPackage(deleted));
        }
예제 #4
0
        /// <summary>
        /// Checks that the current batch of catalog entries contains the entry that was created from the current state of the database.
        /// </summary>
        /// <remarks>
        /// Our validations depend on the fact that the database and V3 are expected to have the same version of a package.
        /// If the catalog entry we're running validations on, which is supposed to represent the current state of V3, is less recent than the database, then we shouldn't run validations.
        /// </remarks>
        protected virtual async Task <ShouldRunTestResult> ShouldRunAsync(ValidationContext context)
        {
            if (context.Entries == null)
            {
                // If we don't have any catalog entries to use to compare timestamps, assume the database and V3 are in the same state and run validations anyway.
                return(ShouldRunTestResult.Yes);
            }

            var timestampDatabase = await context.GetTimestampMetadataDatabaseAsync();

            var timestampCatalog = await PackageTimestampMetadata.FromCatalogEntries(context.Client, context.Entries);

            if (!timestampDatabase.Last.HasValue)
            {
                throw new TimestampComparisonException(timestampDatabase, timestampCatalog,
                                                       "Cannot get timestamp data for package from the database!");
            }

            if (!timestampCatalog.Last.HasValue)
            {
                throw new TimestampComparisonException(timestampDatabase, timestampCatalog,
                                                       "Cannot get timestamp data for package from the catalog!");
            }

            if (timestampCatalog.Last > timestampDatabase.Last)
            {
                throw new TimestampComparisonException(timestampDatabase, timestampCatalog,
                                                       "The timestamp in the catalog is newer than the timestamp in the database! This should never happen because all data flows from the feed into the catalog!");
            }

            return(timestampCatalog.Last == timestampDatabase.Last
                   // If the timestamp metadata in the catalog is EQUAL to that of the database, we are looking at the latest catalog entry that corresponds with this package, so run the test.
                ? ShouldRunTestResult.Yes
                   // If the timestamp metadata in the catalog is LESS than that of the database, we must not be looking at the latest entry that corresponds with this package, so we must attempt this test again later with more information.
                : ShouldRunTestResult.RetryLater);
        }
예제 #5
0
        /// <summary>
        /// Parses the feed for the package specified by the <see cref="ValidationContext"/> and returns a <see cref="PackageTimestampMetadata"/>.
        /// If the package is missing from the feed, returns the package's deletion audit record timestamp.
        /// </summary>
        public async Task <PackageTimestampMetadata> GetAsync(ValidationContext context)
        {
            var feedPackageDetails = await FeedHelpers.GetPackage(
                context.Client,
                _source,
                context.Package.Id,
                context.Package.Version.ToString());

            if (feedPackageDetails != null)
            {
                return(PackageTimestampMetadata.CreateForPackageExistingOnFeed(
                           feedPackageDetails.CreatedDate,
                           feedPackageDetails.LastEditedDate));
            }

            DateTime?deleted = null;

            if (context.DeletionAuditEntries.Any())
            {
                deleted = context.DeletionAuditEntries.Max(entry => entry.TimestampUtc);
            }

            return(PackageTimestampMetadata.CreateForPackageMissingFromFeed(deleted));
        }