Skip to content
This repository has been archived by the owner on Jul 30, 2024. It is now read-only.
/ NuGet.Jobs Public archive

Status - unit tests #580

Merged
merged 5 commits into from
Oct 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/StatusAggregator/Export/EventExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;
using NuGet.Jobs.Extensions;
Expand Down
1 change: 0 additions & 1 deletion src/StatusAggregator/Export/IEventExporter.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Generic;
using NuGet.Services.Status;
using NuGet.Services.Status.Table;

Expand Down
2 changes: 1 addition & 1 deletion src/StatusAggregator/Factory/AggregationStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public async Task<bool> CanBeAggregatedByAsync(ParsedIncident input, TAggregatio

// To guarantee that the aggregation reflects the latest information and is actually active, we must update it.
await _aggregationUpdater.UpdateAsync(aggregationEntity, input.StartTime);
if (!aggregationEntity.IsActive || input.IsActive)
if (!aggregationEntity.IsActive && input.IsActive)
{
_logger.LogInformation("Cannot link entity to aggregation because it has been deactivated and the incident has not been.");
return false;
Expand Down
26 changes: 20 additions & 6 deletions src/StatusAggregator/Job.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Autofac.Core;
using Autofac.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.WindowsAzure.Storage;
using Newtonsoft.Json.Linq;
using NuGet.Jobs;
Expand Down Expand Up @@ -46,6 +47,7 @@ public override void Init(IServiceContainer serviceContainer, IDictionary<string

AddStorage(containerBuilder);
AddFactoriesAndUpdaters(containerBuilder);
AddIncidentRegexParser(containerBuilder);
AddExporters(containerBuilder);
AddEntityCollector(containerBuilder);

Expand Down Expand Up @@ -95,13 +97,13 @@ private static void AddManualStatusChangeHandling(IServiceCollection serviceColl

private static void AddParsing(IServiceCollection serviceCollection)
{
serviceCollection.AddTransient<IIncidentParsingFilter, SeverityFilter>();
serviceCollection.AddTransient<IIncidentParsingFilter, EnvironmentFilter>();
serviceCollection.AddTransient<IIncidentRegexParsingFilter, SeverityRegexParsingFilter>();
serviceCollection.AddTransient<IIncidentRegexParsingFilter, EnvironmentRegexParsingFilter>();

serviceCollection.AddTransient<IIncidentParser, OutdatedSearchServiceInstanceIncidentParser>();
serviceCollection.AddTransient<IIncidentParser, PingdomIncidentParser>();
serviceCollection.AddTransient<IIncidentParser, ValidationDurationIncidentParser>();
serviceCollection.AddTransient<IIncidentParser, TrafficManagerEndpointStatusIncidentParser>();
serviceCollection.AddTransient<IIncidentRegexParsingHandler, OutdatedSearchServiceInstanceIncidentRegexParsingHandler>();
serviceCollection.AddTransient<IIncidentRegexParsingHandler, PingdomIncidentRegexParsingHandler>();
serviceCollection.AddTransient<IIncidentRegexParsingHandler, ValidationDurationIncidentRegexParsingHandler>();
serviceCollection.AddTransient<IIncidentRegexParsingHandler, TrafficManagerEndpointStatusIncidentRegexParsingHandler>();

serviceCollection.AddTransient<IAggregateIncidentParser, AggregateIncidentParser>();
}
Expand Down Expand Up @@ -249,6 +251,18 @@ private static void AddEventUpdater(ContainerBuilder containerBuilder)
.As<IComponentAffectingEntityUpdater<EventEntity>>();
}

private static void AddIncidentRegexParser(ContainerBuilder containerBuilder)
{
containerBuilder
.RegisterAdapter<IIncidentRegexParsingHandler, IIncidentParser>(
(ctx, handler) =>
{
return new IncidentRegexParser(
handler,
ctx.Resolve<ILogger<IncidentRegexParser>>());
});
}

private static void AddEntityCollector(ContainerBuilder containerBuilder)
{
containerBuilder
Expand Down
18 changes: 4 additions & 14 deletions src/StatusAggregator/Messages/IMessageContentBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,13 @@ namespace StatusAggregator.Messages
public interface IMessageContentBuilder
{
/// <summary>
/// Tries to get contents for a message of type <paramref name="type"/> affecting <paramref name="component"/>.
/// Builds contents for a message of type <paramref name="type"/> affecting <paramref name="component"/>.
/// </summary>
/// <param name="contents">The content of the message.</param>
/// <returns>
/// True if contents for the message can be generated.
/// False otherwise.
/// </returns>
string GetContentsForMessageHelper(MessageType type, IComponent component);
string Build(MessageType type, IComponent component);

/// <summary>
/// Tries to get contents for a message of type <paramref name="type"/> affecting <paramref name="component"/> with status <paramref name="status"/>.
/// Builds contents for a message of type <paramref name="type"/> affecting <paramref name="component"/> with status <paramref name="status"/>.
/// </summary>
/// <param name="contents">The content of the message.</param>
/// <returns>
/// True if contents for the message can be generated.
/// False otherwise.
/// </returns>
string GetContentsForMessageHelper(MessageType type, IComponent component, ComponentStatus status);
string Build(MessageType type, IComponent component, ComponentStatus status);
}
}
4 changes: 2 additions & 2 deletions src/StatusAggregator/Messages/IMessageFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ public interface IMessageFactory
/// <summary>
/// Creates a message for <paramref name="eventEntity"/> at <paramref name="time"/> of type <paramref name="type"/> affecting <paramref name="component"/>.
/// </summary>
Task<MessageEntity> CreateMessageAsync(EventEntity eventEntity, DateTime time, MessageType type, IComponent component);
Task CreateMessageAsync(EventEntity eventEntity, DateTime time, MessageType type, IComponent component);

/// <summary>
/// Creates a message for <paramref name="eventEntity"/> at <paramref name="time"/> of type <paramref name="type"/> affecting <paramref name="component"/> with status <paramref name="status"/>.
/// </summary>
Task<MessageEntity> CreateMessageAsync(EventEntity eventEntity, DateTime time, MessageType type, IComponent component, ComponentStatus status);
Task CreateMessageAsync(EventEntity eventEntity, DateTime time, MessageType type, IComponent component, ComponentStatus status);

/// <summary>
/// Updates the message for <paramref name="eventEntity"/> at <paramref name="time"/> of type <paramref name="type"/> affecting <paramref name="component"/>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public IEnumerable<MessageChangeEvent> Get(EventEntity eventEntity, DateTime cur
var startTime = linkedGroup.StartTime;
_logger.LogInformation("Incident group started at {StartTime}.", startTime);
events.Add(new MessageChangeEvent(startTime, path, status, MessageType.Start));
if (linkedGroup.EndTime.HasValue)
if (!linkedGroup.IsActive)
{
var endTime = linkedGroup.EndTime.Value;
_logger.LogInformation("Incident group ended at {EndTime}.", endTime);
Expand Down
22 changes: 11 additions & 11 deletions src/StatusAggregator/Messages/MessageContentBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,22 @@ public MessageContentBuilder(ILogger<MessageContentBuilder> logger)
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

public string GetContentsForMessageHelper(
public string Build(
MessageType type,
IComponent component)
{
return GetContentsForMessageHelper(type, component, component.Status);
return Build(type, component, component.Status);
}

public string GetContentsForMessageHelper(
public string Build(
MessageType type,
IComponent component,
ComponentStatus status)
{
return GetContentsForMessageHelper(type, component.Path, status);
return Build(type, component.Path, status);
}

private string GetContentsForMessageHelper(
private string Build(
MessageType type,
string path,
ComponentStatus status)
Expand All @@ -51,23 +51,23 @@ private string GetContentsForMessageHelper(

_logger.LogInformation("Using template {MessageTemplate}.", messageTemplate);

var componentName = GetPrettyName(path);
_logger.LogInformation("Using {ComponentName} for name of component.", componentName);
var nameString = GetName(path);
_logger.LogInformation("Using {ComponentName} for name of component.", nameString);

var actionDescription = GetActionDescriptionFromPath(path);
if (actionDescription == null)
{
throw new ArgumentException("Could not find an action description for path.", nameof(path));
}

var componentStatus = status.ToString().ToLowerInvariant();
var contents = string.Format(messageTemplate, componentName, componentStatus, actionDescription);
var statusString = status.ToString().ToLowerInvariant();
var contents = string.Format(messageTemplate, nameString, statusString, actionDescription);
_logger.LogInformation("Returned {Contents} for contents of message.", contents);
return contents;
}
}

private string GetPrettyName(string path)
private string GetName(string path)
{
var componentNames = ComponentUtility.GetNames(path);
return string.Join(" ", componentNames.Skip(1).Reverse());
Expand All @@ -83,7 +83,7 @@ private string GetActionDescriptionFromPath(string path)
{
return _actionDescriptionForComponentPathMap
.FirstOrDefault(m => m.Matches(path))?
.ActionDescription; ;
.ActionDescription;
}

/// <remarks>
Expand Down
11 changes: 5 additions & 6 deletions src/StatusAggregator/Messages/MessageFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ public MessageFactory(
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

public Task<MessageEntity> CreateMessageAsync(EventEntity eventEntity, DateTime time, MessageType type, IComponent component)
public Task CreateMessageAsync(EventEntity eventEntity, DateTime time, MessageType type, IComponent component)
{
return CreateMessageAsync(eventEntity, time, type, component, component.Status);
}

public async Task<MessageEntity> CreateMessageAsync(EventEntity eventEntity, DateTime time, MessageType type, IComponent component, ComponentStatus status)
public async Task CreateMessageAsync(EventEntity eventEntity, DateTime time, MessageType type, IComponent component, ComponentStatus status)
{
using (_logger.Scope("Creating new message of type {Type} for event {EventRowKey} at {Timestamp} affecting {ComponentPath} with status {ComponentStatus}.",
type, eventEntity.RowKey, time, component.Path, status))
Expand All @@ -42,15 +42,14 @@ public async Task<MessageEntity> CreateMessageAsync(EventEntity eventEntity, Dat
if (existingMessage != null)
{
_logger.LogInformation("Message already exists, will not recreate.");
return existingMessage;
return;
}

var contents = _builder.GetContentsForMessageHelper(type, component, status);
var contents = _builder.Build(type, component, status);
var messageEntity = new MessageEntity(eventEntity, time, contents, type);
_logger.LogInformation("Creating message with time {MessageTimestamp} and contents {MessageContents}.",
messageEntity.Time, messageEntity.Contents);
await _table.InsertAsync(messageEntity);
return messageEntity;
}
}

Expand Down Expand Up @@ -81,7 +80,7 @@ public async Task UpdateMessageAsync(EventEntity eventEntity, DateTime time, Mes
return;
}

var newContents = _builder.GetContentsForMessageHelper(type, component);
var newContents = _builder.Build(type, component);
_logger.LogInformation("Replacing contents of message with time {MessageTimestamp} and contents {OldMessageContents} with {NewMessageContents}.",
existingMessage.Time, existingMessage.Contents, newContents);
existingMessage.Contents = newContents;
Expand Down
33 changes: 0 additions & 33 deletions src/StatusAggregator/Parse/EnvironmentPrefixIncidentParser.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using NuGet.Services.Incidents;

namespace StatusAggregator.Parse
{
/// <summary>
/// Subclass of <see cref="IncidentRegexParsingHandler"/> that expects <see cref="Incident"/>s are prefixed with "[ENVIRONMENT]".
/// </summary>
public abstract class EnvironmentPrefixIncidentRegexParsingHandler : IncidentRegexParsingHandler
{
public EnvironmentPrefixIncidentRegexParsingHandler(
string subtitleRegEx,
IEnumerable<IIncidentRegexParsingFilter> filters)
: base(
PrependEnvironmentRegexGroup(subtitleRegEx),
filters)
{
if (!filters.Any(f => f is EnvironmentRegexParsingFilter))
{
throw new ArgumentException(
$"A {nameof(EnvironmentPrefixIncidentRegexParsingHandler)} must be run with an {nameof(EnvironmentRegexParsingFilter)}!",
nameof(filters));
}
}

private static string PrependEnvironmentRegexGroup(string subtitleRegEx)
{
return $@"\[(?<{EnvironmentRegexParsingFilter.EnvironmentGroupName}>.*)\] {subtitleRegEx}";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ namespace StatusAggregator.Parse
/// <summary>
/// Expects that the <see cref="Incident"/> contains a <see cref="Group"/> named <see cref="EnvironmentGroupName"/> with a whitelisted value.
/// </summary>
public class EnvironmentFilter : IIncidentParsingFilter
public class EnvironmentRegexParsingFilter : IIncidentRegexParsingFilter
{
public const string EnvironmentGroupName = "Environment";

private IEnumerable<string> _environments { get; }

private readonly ILogger<EnvironmentFilter> _logger;
private readonly ILogger<EnvironmentRegexParsingFilter> _logger;

public EnvironmentFilter(
public EnvironmentRegexParsingFilter(
StatusAggregatorConfiguration configuration,
ILogger<EnvironmentFilter> logger)
ILogger<EnvironmentRegexParsingFilter> logger)
{
_environments = configuration?.Environments ?? throw new ArgumentNullException(nameof(configuration));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
namespace StatusAggregator.Parse
{
/// <summary>
/// An additional filter that can be applied to a <see cref="IncidentParser"/>
/// An additional filter that can be applied to a <see cref="IncidentRegexParser"/>
/// </summary>
public interface IIncidentParsingFilter
public interface IIncidentRegexParsingFilter
{
/// <summary>
/// Returns whether or not an <see cref="IncidentParser"/> should parse <paramref name="incident"/>.
/// Returns whether or not an <see cref="IncidentRegexParser"/> should parse <paramref name="incident"/>.
/// </summary>
bool ShouldParse(Incident incident, GroupCollection groups);
}
Expand Down
37 changes: 37 additions & 0 deletions src/StatusAggregator/Parse/IIncidentRegexParsingHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.Text.RegularExpressions;
using NuGet.Services.Incidents;
using NuGet.Services.Status;

namespace StatusAggregator.Parse
{
public interface IIncidentRegexParsingHandler
{
string RegexPattern { get; }
IReadOnlyCollection<IIncidentRegexParsingFilter> Filters { get; }

/// <summary>
/// Attempts to parse a <see cref="ParsedIncident.AffectedComponentPath"/> from <paramref name="incident"/>.
/// </summary>
/// <param name="affectedComponentPath">
/// The <see cref="ParsedIncident.AffectedComponentPath"/> parsed from <paramref name="incident"/> or <c>null</c> if <paramref name="incident"/> could not be parsed.
/// </param>
/// <returns>
/// <c>true</c> if a <see cref="ParsedIncident.AffectedComponentPath"/> can be parsed from <paramref name="incident"/> and <c>false</c> otherwise.
/// </returns>
bool TryParseAffectedComponentPath(Incident incident, GroupCollection groups, out string affectedComponentPath);

/// <summary>
/// Attempts to parse a <see cref="ParsedIncident.AffectedComponentStatus"/> from <paramref name="incident"/>.
/// </summary>
/// <param name="affectedComponentStatus"></param>
/// The <see cref="ParsedIncident.AffectedComponentStatus"/> parsed from <paramref name="incident"/> or <see cref="default(ComponentStatus)"/> if <paramref name="incident"/> could not be parsed.
/// <returns>
/// <c>true</c> if a <see cref="ParsedIncident.AffectedComponentStatus"/> can be parsed from <paramref name="incident"/> and <c>false</c> otherwise.
/// </returns>
bool TryParseAffectedComponentStatus(Incident incident, GroupCollection groups, out ComponentStatus affectedComponentStatus);
}
}
Loading