public async Task SaveImageScanResultCouldSaveNewEntity()
        {
            // Arrange
            await using var context = JosekiTestsDb.CreateUniqueContext();
            var parser = new ConfigurationParser("config.sample.yaml");
            var db     = new MssqlJosekiDatabase(context, parser);
            var cves   = new List <ImageScanToCve>
            {
                new ImageScanToCve {
                    InternalCveId = 1, Target = Guid.NewGuid().ToString(), UsedPackage = Guid.NewGuid().ToString(), UsedPackageVersion = Guid.NewGuid().ToString()
                },
                new ImageScanToCve {
                    InternalCveId = 2, Target = Guid.NewGuid().ToString(), UsedPackage = Guid.NewGuid().ToString(), UsedPackageVersion = Guid.NewGuid().ToString()
                },
                new ImageScanToCve {
                    InternalCveId = 3, Target = Guid.NewGuid().ToString(), UsedPackage = Guid.NewGuid().ToString(), UsedPackageVersion = Guid.NewGuid().ToString()
                },
            };
            var scan = new ImageScanResultWithCVEs
            {
                Date        = DateTime.UtcNow,
                Id          = Guid.NewGuid().ToString(),
                Description = Guid.NewGuid().ToString(),
                ImageTag    = Guid.NewGuid().ToString(),
                Status      = ImageScanStatus.Succeeded,
                FoundCVEs   = cves,
            };

            // Act & Assert
            context.ImageScanResult.Should().HaveCount(0);
            context.ImageScanResultToCve.Should().HaveCount(0);

            await db.SaveImageScanResult(scan);

            context.ImageScanResult.Should().HaveCount(1);
            context.ImageScanResultToCve.Should().HaveCount(cves.Count);

            var actual = await context.ImageScanResult.FirstAsync();

            actual.Date.Should().Be(scan.Date);
            actual.ExternalId.Should().Be(scan.Id);
            actual.Description.Should().Be(scan.Description);
            actual.ImageTag.Should().Be(scan.ImageTag);
            actual.Status.Should().Be(joseki.db.entities.ImageScanStatus.Succeeded);

            foreach (var actualCve in await context.ImageScanResultToCve.ToArrayAsync())
            {
                var expectedCve = cves.First(i => i.InternalCveId == actualCve.CveId);
                actualCve.Target.Should().Be(expectedCve.Target);
                actualCve.UsedPackage.Should().Be(expectedCve.UsedPackage);
                actualCve.UsedPackageVersion.Should().Be(expectedCve.UsedPackageVersion);
            }
        }
        public async Task SaveImageScanResultUpdatesInProgressCheckResults()
        {
            // Arrange
            await using var context = JosekiTestsDb.CreateUniqueContext();

            var scan = new ImageScanResultWithCVEs
            {
                Date        = DateTime.UtcNow,
                Id          = Guid.NewGuid().ToString(),
                Description = Guid.NewGuid().ToString(),
                ImageTag    = Guid.NewGuid().ToString(),
                Status      = ImageScanStatus.Succeeded,
                FoundCVEs   = new List <ImageScanToCve>
                {
                    new ImageScanToCve {
                        InternalCveId = 1, Target = Guid.NewGuid().ToString(), UsedPackage = Guid.NewGuid().ToString(), UsedPackageVersion = Guid.NewGuid().ToString()
                    },
                    new ImageScanToCve {
                        InternalCveId = 2, Target = Guid.NewGuid().ToString(), UsedPackage = Guid.NewGuid().ToString(), UsedPackageVersion = Guid.NewGuid().ToString()
                    },
                    new ImageScanToCve {
                        InternalCveId = 3, Target = Guid.NewGuid().ToString(), UsedPackage = Guid.NewGuid().ToString(), UsedPackageVersion = Guid.NewGuid().ToString()
                    },
                },
                Counters = new[]
                {
                    new VulnerabilityCounter {
                        Count = 1, Severity = CveSeverity.High
                    },
                    new VulnerabilityCounter {
                        Count = 2, Severity = CveSeverity.Medium
                    },
                },
            };

            // only the first one should be updated
            var checkResults = new[]
            {
                new CheckResultEntity {
                    Id = 100, Value = joseki.db.entities.CheckValue.InProgress, ComponentId = $"/k8s/.../image/{scan.ImageTag}", DateUpdated = DateTime.UtcNow.AddDays(-1)
                },
                new CheckResultEntity {
                    Id = 200, Value = joseki.db.entities.CheckValue.InProgress, ComponentId = $"/k8s/.../image/{Guid.NewGuid()}", DateUpdated = DateTime.UtcNow.AddDays(-1)
                },
                new CheckResultEntity {
                    Id = 300, Value = joseki.db.entities.CheckValue.Succeeded, ComponentId = $"/k8s/.../image/{scan.ImageTag}", DateUpdated = DateTime.UtcNow.AddDays(-1)
                },
            };

            // this is the hack -_-
            // Use sync version, because it does not update DateUpdated & DateCreated
            context.CheckResult.AddRange(checkResults);
            context.SaveChanges();

            var parser = new ConfigurationParser("config.sample.yaml");
            var db     = new MssqlJosekiDatabase(context, parser);

            // Act & Assert
            var saveRequestedAt = DateTime.UtcNow;
            await db.SaveImageScanResult(scan);

            var updatedCheckResults = await context.CheckResult.Where(i => i.DateUpdated >= saveRequestedAt).ToArrayAsync();

            updatedCheckResults.Should().HaveCount(1);
            updatedCheckResults.First().Id.Should().Be(100);
        }
        public async Task SaveImageScanResultCouldUpdateExistingEntity()
        {
            // Arrange
            await using var context = JosekiTestsDb.CreateUniqueContext();

            var queuedScan = new ImageScanResultEntity
            {
                Date        = DateTime.UtcNow.AddMinutes(-10),
                ExternalId  = Guid.NewGuid().ToString(),
                Description = Guid.NewGuid().ToString(),
                ImageTag    = Guid.NewGuid().ToString(),
                Status      = joseki.db.entities.ImageScanStatus.Queued,
            };

            context.Set <ImageScanResultEntity>().Add(queuedScan);
            await context.SaveChangesAsync();

            var scan = new ImageScanResultWithCVEs
            {
                Date        = DateTime.UtcNow,
                Id          = queuedScan.ExternalId,
                Description = Guid.NewGuid().ToString(),
                ImageTag    = queuedScan.ImageTag,
                Status      = ImageScanStatus.Succeeded,
                FoundCVEs   = new List <ImageScanToCve>
                {
                    new ImageScanToCve {
                        InternalCveId = 1, Target = Guid.NewGuid().ToString(), UsedPackage = Guid.NewGuid().ToString(), UsedPackageVersion = Guid.NewGuid().ToString()
                    },
                    new ImageScanToCve {
                        InternalCveId = 2, Target = Guid.NewGuid().ToString(), UsedPackage = Guid.NewGuid().ToString(), UsedPackageVersion = Guid.NewGuid().ToString()
                    },
                    new ImageScanToCve {
                        InternalCveId = 3, Target = Guid.NewGuid().ToString(), UsedPackage = Guid.NewGuid().ToString(), UsedPackageVersion = Guid.NewGuid().ToString()
                    },
                },
            };

            var parser = new ConfigurationParser("config.sample.yaml");
            var db     = new MssqlJosekiDatabase(context, parser);

            // Act & Assert
            context.ImageScanResult.Should().HaveCount(1);
            context.ImageScanResultToCve.Should().HaveCount(0);

            await db.SaveImageScanResult(scan);

            context.ImageScanResult.Should().HaveCount(1);
            context.ImageScanResultToCve.Should().HaveCount(scan.FoundCVEs.Count);

            // Only Date, Description, Status, and CVEs should be updated
            var actual = await context.ImageScanResult.FirstAsync();

            actual.Date.Should().Be(scan.Date);
            actual.Description.Should().Be(scan.Description);
            actual.Status.Should().Be(joseki.db.entities.ImageScanStatus.Succeeded);

            foreach (var actualCve in await context.ImageScanResultToCve.ToArrayAsync())
            {
                var expectedCve = scan.FoundCVEs.First(i => i.InternalCveId == actualCve.CveId);
                actualCve.Target.Should().Be(expectedCve.Target);
                actualCve.UsedPackage.Should().Be(expectedCve.UsedPackage);
                actualCve.UsedPackageVersion.Should().Be(expectedCve.UsedPackageVersion);
            }
        }