public async Task ResolvesGapInData(bool shouldResolve)
        {
            // Arrange
            var input = new List <Discrepancy> {
                new Discrepancy {
                    DateFirstOffense = DateTime.UtcNow,
                    Type             = DiscrepancyType.GapInData,
                    MetricSource     = "the-source-1",
                    MetricType       = Metrics.CpuLoad,
                }
            };

            var metric = new Metric
            {
                Type   = Metrics.CpuLoad.AsInt(),
                Source = "the-source-1"
            };

            var context = _serviceProvider.GetRequiredService <IDataContext>();
            await context.Metrics.AddAsync(metric);

            await context.NumericDataPoints.AddRangeAsync(
                new NumericDataPoint
            {
                Metric    = metric,
                Value     = 50,
                Timestamp = DateTime.UtcNow.AddMinutes(-2)
            },
                new NumericDataPoint
            {
                Metric    = metric,
                Value     = 92,
                Timestamp = DateTime.UtcNow.AddMinutes(shouldResolve ? 1 : -1)
            }
                );

            await context.SaveChangesAsync();

            var discrepancyService = new DiscrepancyService(
                new Mock <ILogger <DiscrepancyService> >().Object,
                context,
                new Mock <INotificationService>().Object,
                new Mock <IConfiguration>().Object
                );

            // Act
            var actual = await discrepancyService.FindResolvedDiscrepanciesAsync(input);

            // Assert
            if (shouldResolve)
            {
                Assert.NotEmpty(actual);
                Assert.Equal(input, actual);
            }
            else
            {
                Assert.Empty(actual);
            }
        }
        public async Task ResolvesLowHealth(bool shouldResolve)
        {
            // Arrange
            var input = new List <Discrepancy> {
                new Discrepancy {
                    DateFirstOffense = DateTime.UtcNow,
                    Type             = DiscrepancyType.LowHealth,
                    MetricSource     = "the-source-1",
                    MetricType       = Metrics.Health,
                }
            };

            var metric = new Metric
            {
                Type   = Metrics.Health.AsInt(),
                Source = "the-source-1"
            };

            var context = _serviceProvider.GetRequiredService <IDataContext>();
            await context.Metrics.AddAsync(metric);

            await context.HealthReports.AddRangeAsync(
                DiscrepancyServiceTest.GenerateHealthReport(true, metric, DateTime.UtcNow.AddMinutes(-1)),
                DiscrepancyServiceTest.GenerateHealthReport(false, metric, DateTime.UtcNow.AddMinutes(1)),
                DiscrepancyServiceTest.GenerateHealthReport(false, metric, DateTime.UtcNow.AddMinutes(2)),
                DiscrepancyServiceTest.GenerateHealthReport(shouldResolve, metric, DateTime.UtcNow.AddMinutes(3))
                );

            await context.SaveChangesAsync();

            var config = new Mock <IConfiguration>();

            config
            .SetupGet(conf => conf["ServiceManager:DiscrepancyService:Health:Threshold"])
            .Returns(99.ToString());

            var discrepancyService = new DiscrepancyService(
                new Mock <ILogger <DiscrepancyService> >().Object,
                context,
                new Mock <INotificationService>().Object,
                config.Object
                );

            // Act
            var actual = await discrepancyService.FindResolvedDiscrepanciesAsync(input);

            // Assert
            if (shouldResolve)
            {
                Assert.NotEmpty(actual);
                Assert.Equal(input, actual);
            }
            else
            {
                Assert.Empty(actual);
            }
        }
        public async Task WarnsAboutResolvedDiscrepanciesInResolve()
        {
            // Arrange
            var logger = new Mock <ILogger <DiscrepancyService> >();

            var discrepancyService = new DiscrepancyService(
                logger.Object,
                new Mock <IDataContext>().Object,
                new Mock <INotificationService>().Object,
                new Mock <IConfiguration>().Object
                );

            var input = new List <Discrepancy> {
                new Discrepancy {
                    DateFirstOffense = DateTime.UtcNow,
                    Type             = DiscrepancyType.GapInData,
                    MetricSource     = "the-source-1",
                    MetricType       = Metrics.CpuLoad,
                    Resolved         = true
                },
                new Discrepancy {
                    DateFirstOffense = DateTime.UtcNow,
                    Type             = DiscrepancyType.GapInData,
                    MetricSource     = "the-source-2",
                    MetricType       = Metrics.CpuLoad,
                    Resolved         = true
                }
            };

            // Act
            var actual = await discrepancyService.FindResolvedDiscrepanciesAsync(input);

            // Assert
            Assert.Empty(actual);
            logger
            .Verify(
                log => log.Log(
                    LogLevel.Warning,
                    It.IsAny <EventId>(),
                    It.IsAny <FormattedLogValues>(),
                    It.IsAny <Exception>(),
                    It.IsAny <Func <object, Exception, string> >()
                    ),
                Times.Exactly(2)
                );
        }
        public async Task ResolvesHighLoad(bool shouldResolve)
        {
            // Arrange
            var input = new List <Discrepancy> {
                new Discrepancy {
                    DateFirstOffense = DateTime.UtcNow,
                    Type             = DiscrepancyType.HighLoad,
                    MetricSource     = "the-source-1",
                    MetricType       = Metrics.CpuLoad,
                }
            };

            var metric = new Metric
            {
                Type   = Metrics.CpuLoad.AsInt(),
                Source = "the-source-1"
            };

            var context = _serviceProvider.GetRequiredService <IDataContext>();
            await context.Metrics.AddAsync(metric);

            await context.NumericDataPoints.AddRangeAsync(
                new NumericDataPoint
            {
                Metric    = metric,
                Value     = 50,
                Timestamp = DateTime.UtcNow.AddMinutes(-1)
            },
                new NumericDataPoint
            {
                Metric    = metric,
                Value     = 95,
                Timestamp = DateTime.UtcNow.AddMinutes(1)
            },
                new NumericDataPoint
            {
                Metric    = metric,
                Value     = 91,
                Timestamp = DateTime.UtcNow.AddMinutes(2)
            },
                new NumericDataPoint
            {
                Metric    = metric,
                Value     = shouldResolve ? 85 : 92,
                Timestamp = DateTime.UtcNow.AddMinutes(3)
            }
                );

            await context.SaveChangesAsync();

            var config = new Mock <IConfiguration>();

            config
            .SetupGet(conf => conf["ServiceManager:DiscrepancyService:Load:Threshold"])
            .Returns(90.ToString());

            var discrepancyService = new DiscrepancyService(
                new Mock <ILogger <DiscrepancyService> >().Object,
                context,
                new Mock <INotificationService>().Object,
                config.Object
                );

            // Act
            var actual = await discrepancyService.FindResolvedDiscrepanciesAsync(input);

            // Assert
            if (shouldResolve)
            {
                Assert.NotEmpty(actual);
                Assert.Equal(input, actual);
            }
            else
            {
                Assert.Empty(actual);
            }
        }
        public async Task ResolvesPingFailure(bool shouldResolve)
        {
            // Arrange
            var input = new List <Discrepancy> {
                new Discrepancy {
                    DateFirstOffense = DateTime.UtcNow,
                    Type             = DiscrepancyType.PingFailedNTimes,
                    MetricSource     = "lolchik.com",
                    MetricType       = Metrics.Ping,
                }
            };

            var metric = new Metric
            {
                Type   = Metrics.Ping.AsInt(),
                Source = "lolchik.com"
            };

            var context = _serviceProvider.GetRequiredService <IDataContext>();
            await context.Metrics.AddAsync(metric);

            await context.PingDataPoints.AddRangeAsync(
                new PingDataPoint
            {
                Metric    = metric,
                Success   = true,
                Timestamp = DateTime.UtcNow.AddMinutes(-1)
            },
                new PingDataPoint
            {
                Metric    = metric,
                Success   = false,
                Timestamp = DateTime.UtcNow.AddMinutes(1)
            },
                new PingDataPoint
            {
                Metric    = metric,
                Success   = false,
                Timestamp = DateTime.UtcNow.AddMinutes(2)
            },
                new PingDataPoint
            {
                Metric    = metric,
                Success   = shouldResolve,
                Timestamp = DateTime.UtcNow.AddMinutes(3)
            }
                );

            await context.SaveChangesAsync();

            var discrepancyService = new DiscrepancyService(
                new Mock <ILogger <DiscrepancyService> >().Object,
                context,
                new Mock <INotificationService>().Object,
                new Mock <IConfiguration>().Object
                );

            // Act
            var actual = await discrepancyService.FindResolvedDiscrepanciesAsync(input);

            // Assert
            if (shouldResolve)
            {
                Assert.NotEmpty(actual);
                Assert.Equal(input, actual);
            }
            else
            {
                Assert.Empty(actual);
            }
        }