Skip to content
Snippets Groups Projects
Commit f18febdd authored by Dmytro Bogatov's avatar Dmytro Bogatov :two_hearts:
Browse files

Merge branch '24-verbosity-setting' into 'master'

Resolve "Verbosity setting"

Closes #24

See merge request !12
parents 859b502b f26640e6
Branches
No related tags found
No related merge requests found
Pipeline #
......@@ -110,6 +110,7 @@ Configuration spec:
NotificationService: # Settings for notification service of the app
Enabled: true # Whether to use the service
Interval: 20 # How many seconds to wait between re-runs of the service
Verbosity: "normal" # How verbose the messages should be. "normal" will include grouping by severity and greetings. "less" will include messages, their timestamps and number of outstanding issues only.
TimeZone: "America/New_York" # Preferred time zone for displaying dates and times in notifications
Frequencies: # Number of seconds to wait before sending out notifications of given severity
Low: 86400 # Example: notifications of low severity will be sent no more than once in 86400 seconds
......
......@@ -20,5 +20,7 @@ ServiceManager:
Interval: 10
Gaps:
MaxDifference: 5
NotificationService:
Verbosity: "less"
Logging:
MinLogLevel: "Debug"
......@@ -93,6 +93,7 @@ ServiceManager:
Enabled: true
Interval: 30
TimeZone: "America/New_York"
Verbosity: "normal"
Frequencies:
Low: 86400
Medium: 360
......
......@@ -79,7 +79,7 @@ namespace StatusMonitor.Shared.Services
.OrderBy(ntf => ntf.DateCreated)
.ToListAsync();
var message = ComposeMessage(notifications);
var message = await ComposeMessageAsync(notifications);
await _email.SendEmailAsync(
new string[] { _config["Secrets:Email:ToEmail"] },
......@@ -148,12 +148,24 @@ namespace StatusMonitor.Shared.Services
return true;
}
internal async Task<string> GenerateUnresolvedDiscrepanciesNoteAsync() {
var unresolved = await _context.Discrepancies.Where(d => !d.Resolved).CountAsync();
return
unresolved == 0 ?
"There are no outstanding issues. Well done." :
$"There {(unresolved == 1 ? "is" : "are")} still outstanding {unresolved} issue{(unresolved == 1 ? "" : "s")}."
;
}
/// <summary>
/// Generate a message containing all given notifications grouped by severities
/// </summary>
/// <param name="notifications">List of notifications to include in the message</param>
/// <returns>The composed message</returns>
internal string ComposeMessage(IEnumerable<Notification> notifications) =>
internal async Task<string> ComposeMessageAsync(IEnumerable<Notification> notifications) =>
_config["ServiceManager:NotificationService:Verbosity"] == "normal" ?
$@"
Dear recipient,
......@@ -174,9 +186,30 @@ namespace StatusMonitor.Shared.Services
.Aggregate((self, next) => $"{self}{Environment.NewLine}{next}")
}
{await GenerateUnresolvedDiscrepanciesNoteAsync()}
Always yours,
Notificator
"
.Replace("\t", "");
.Replace("\t", "")
:
$@"
{
notifications
.Select(
ntf => $@"[{
ntf.
DateCreated.
ToStringUsingTimeZone(
_config["ServiceManager:NotificationService:TimeZone"]
)
}] {ntf.Message}"
)
.Aggregate((self, next) => $"{self}{Environment.NewLine}{next}")
}
{await GenerateUnresolvedDiscrepanciesNoteAsync()}
"
.Replace("\t", "")
;
}
}
......@@ -125,6 +125,7 @@ namespace StatusMonitor.Tests.UnitTests
TestIntKey($"ServiceManager:NotificationService:Frequencies:{NotificationSeverity.High.ToString()}");
TestStringKey($"ServiceManager:NotificationService:TimeZone");
TestStringKey($"ServiceManager:NotificationService:Verbosity");
}
private void TestStringKey(string key)
......
......@@ -48,6 +48,9 @@ namespace StatusMonitor.Tests.UnitTests.Services
config => config[$"ServiceManager:NotificationService:Frequencies:{NotificationSeverity.Low.ToString()}"]
)
.Returns($"{24 * 60 * 60}");
mockConfig
.SetupGet(conf => conf["ServiceManager:NotificationService:Verbosity"])
.Returns("normal");
_config = mockConfig.Object;
services.RegisterSharedServices(env, new Mock<IConfiguration>().Object);
......@@ -65,7 +68,7 @@ namespace StatusMonitor.Tests.UnitTests.Services
var notificationService = new NotificationService(
new Mock<ILogger<NotificationService>>().Object,
new Mock<IConfiguration>().Object,
_config,
context,
new Mock<IEmailService>().Object,
new Mock<ISlackService>().Object
......@@ -87,12 +90,10 @@ namespace StatusMonitor.Tests.UnitTests.Services
public void ChecksIfNeedToSend_NoNotifications()
{
// Arrange
var context = _serviceProvider.GetRequiredService<IDataContext>();
var notificationService = new NotificationService(
new Mock<ILogger<NotificationService>>().Object,
new Mock<IConfiguration>().Object,
context,
_config,
_serviceProvider.GetRequiredService<IDataContext>(),
new Mock<IEmailService>().Object,
new Mock<ISlackService>().Object
);
......@@ -175,7 +176,7 @@ namespace StatusMonitor.Tests.UnitTests.Services
[InlineData(NotificationSeverity.High)]
[InlineData(NotificationSeverity.Medium)]
[InlineData(NotificationSeverity.Low)]
public void ComposesMessage(NotificationSeverity severity)
public async Task ComposesMessage(NotificationSeverity severity)
{
// Arrange
var input = new List<Notification> {
......@@ -190,14 +191,14 @@ namespace StatusMonitor.Tests.UnitTests.Services
var notificationService = new NotificationService(
new Mock<ILogger<NotificationService>>().Object,
new Mock<IConfiguration>().Object,
new Mock<IDataContext>().Object,
_config,
_serviceProvider.GetRequiredService<IDataContext>(),
new Mock<IEmailService>().Object,
new Mock<ISlackService>().Object
);
// Act
var actual = notificationService.ComposeMessage(input);
var actual = await notificationService.ComposeMessageAsync(input);
// Assert
Assert.Contains($"Severity {severity}", actual);
......@@ -211,7 +212,7 @@ namespace StatusMonitor.Tests.UnitTests.Services
var notificationService = new NotificationService(
new Mock<ILogger<NotificationService>>().Object,
new Mock<IConfiguration>().Object,
_config,
context,
new Mock<IEmailService>().Object,
new Mock<ISlackService>().Object
......@@ -303,15 +304,13 @@ namespace StatusMonitor.Tests.UnitTests.Services
public async Task ProcessesNotificationQueue_NoData()
{
// Arrange
var context = _serviceProvider.GetRequiredService<IDataContext>();
var mockEmail = new Mock<IEmailService>();
var mockSlack = new Mock<ISlackService>();
var notificationService = new NotificationService(
new Mock<ILogger<NotificationService>>().Object,
_config,
context,
_serviceProvider.GetRequiredService<IDataContext>(),
mockEmail.Object,
mockSlack.Object
);
......@@ -340,18 +339,21 @@ namespace StatusMonitor.Tests.UnitTests.Services
}
[Fact]
public void UsesCorrectTimeZone()
public async Task UsesCorrectTimeZone()
{
// Arrange
var config = new Mock<IConfiguration>();
config
.SetupGet(conf => conf["ServiceManager:NotificationService:TimeZone"])
.Returns("Asia/Kabul");
config
.SetupGet(conf => conf["ServiceManager:NotificationService:Verbosity"])
.Returns("normal");
var notificationService = new NotificationService(
new Mock<ILogger<NotificationService>>().Object,
config.Object,
new Mock<IDataContext>().Object,
_serviceProvider.GetRequiredService<IDataContext>(),
new Mock<IEmailService>().Object,
new Mock<ISlackService>().Object
);
......@@ -368,10 +370,47 @@ namespace StatusMonitor.Tests.UnitTests.Services
var expected = date.ToStringUsingTimeZone("Asia/Kabul");
// Act
var actual = notificationService.ComposeMessage(input);
var actual = await notificationService.ComposeMessageAsync(input);
// Assert
Assert.Contains(expected, actual);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task GeneratesUnresolvedDiscrepanciesNoteAsync(bool discrepancies)
{
// Arrange
var context = _serviceProvider.GetRequiredService<IDataContext>();
if (discrepancies)
{
await context.Discrepancies.AddAsync(new Discrepancy {
Type = DiscrepancyType.GapInData,
MetricType = Metrics.CpuLoad,
MetricSource = "the-source",
DateFirstOffense = DateTime.UtcNow
});
await context.SaveChangesAsync();
}
var notificationService = new NotificationService(
new Mock<ILogger<NotificationService>>().Object,
new Mock<IConfiguration>().Object,
context,
new Mock<IEmailService>().Object,
new Mock<ISlackService>().Object
);
// Act
var actual = await notificationService.GenerateUnresolvedDiscrepanciesNoteAsync();
// Assert
Assert.Contains(discrepancies ? 1.ToString() : "no", actual);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment