-
Notifications
You must be signed in to change notification settings - Fork 18
Add status classes and tests #170
Changes from 7 commits
15fd822
4e12b54
72f5ffd
1ffe907
9b15827
c20ff3d
88a025f
b5be64a
4c6bf3e
7fbd34e
bc7b870
c17481d
7eaf4e3
46d9624
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// 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; | ||
|
||
namespace NuGet.Services.Status | ||
{ | ||
/// <summary> | ||
/// Default implementation of <see cref="IComponent"/>. | ||
/// </summary> | ||
public abstract class Component : IComponent | ||
{ | ||
public string Name { get; } | ||
public string Description { get; } | ||
public abstract ComponentStatus Status { get; set; } | ||
public IEnumerable<IComponent> SubComponents { get; } | ||
IEnumerable<IReadOnlyComponent> IReadOnlyComponent.SubComponents => SubComponents; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Should this guy be public? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed the inheritance so that this property no longer needs to exist. |
||
public string Path => Name; | ||
|
||
public Component( | ||
string name, | ||
string description) | ||
{ | ||
Name = name ?? throw new ArgumentNullException(nameof(name)); | ||
Description = description ?? ""; | ||
SubComponents = Enumerable.Empty<IComponent>(); | ||
} | ||
|
||
public Component( | ||
string name, | ||
string description, | ||
IEnumerable<IComponent> subComponents) | ||
: this(name, description) | ||
{ | ||
SubComponents = subComponents?.Select(s => new SubComponent(s, this)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You should There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. Also made this fix to several other component classes |
||
?? throw new ArgumentNullException(nameof(subComponents)); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// 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. | ||
|
||
namespace NuGet.Services.Status | ||
{ | ||
/// <summary> | ||
/// Describes whether or not a <see cref="IReadOnlyComponent"/> is performing as expected. | ||
/// </summary> | ||
public enum ComponentStatus | ||
{ | ||
/// <summary> | ||
/// The <see cref="IReadOnlyComponent"/> is performing as expected. | ||
/// </summary> | ||
Up, | ||
|
||
/// <summary> | ||
/// Some portion of the <see cref="IReadOnlyComponent"/> is not performing as expected. | ||
/// </summary> | ||
Degraded, | ||
|
||
/// <summary> | ||
/// The <see cref="IReadOnlyComponent"/> is completely unfunctional. | ||
/// </summary> | ||
Down | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// 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.Linq; | ||
|
||
namespace NuGet.Services.Status | ||
{ | ||
public static class ComponentUtility | ||
{ | ||
public static string GetPath(params string[] componentNames) | ||
{ | ||
return string.Join(Constants.ComponentPathDivider.ToString(), componentNames); | ||
} | ||
|
||
public static IReadOnlyComponent GetByPath(this IReadOnlyComponent root, string path) | ||
{ | ||
var componentNames = path.Split(Constants.ComponentPathDivider); | ||
return root.GetByPath(componentNames); | ||
} | ||
|
||
public static IReadOnlyComponent GetByPath(this IReadOnlyComponent root, params string[] componentNames) | ||
{ | ||
if (componentNames.First() != root.Name) | ||
{ | ||
return null; | ||
} | ||
|
||
IReadOnlyComponent component = root; | ||
foreach (var componentName in componentNames.Skip(1)) | ||
{ | ||
component = component.SubComponents.FirstOrDefault(c => c.Name == componentName); | ||
|
||
if (component == null) | ||
{ | ||
break; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If I run There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was a bug. I added tests to make sure it doesn't break again. |
||
} | ||
} | ||
|
||
return component; | ||
} | ||
|
||
public static IComponent GetByPath(this IComponent root, string path) | ||
{ | ||
var componentNames = path.Split(Constants.ComponentPathDivider); | ||
return root.GetByPath(componentNames); | ||
} | ||
|
||
public static IComponent GetByPath(this IComponent root, params string[] componentNames) | ||
{ | ||
if (componentNames.First() != root.Name) | ||
{ | ||
return null; | ||
} | ||
|
||
IComponent component = root; | ||
foreach (var componentName in componentNames.Skip(1)) | ||
{ | ||
component = component.SubComponents.FirstOrDefault(c => c.Name == componentName); | ||
|
||
if (component == null) | ||
{ | ||
break; | ||
} | ||
} | ||
|
||
return component; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// 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. | ||
|
||
namespace NuGet.Services.Status | ||
{ | ||
public static class Constants | ||
{ | ||
/// <summary> | ||
/// Used to construct <see cref="IReadOnlyComponent.Path"/>. | ||
/// </summary> | ||
/// <example> | ||
/// Suppose C is a subcomponent of B which is a subcomponent of A. | ||
/// The path of C is <code>"A" + ComponentPathDivider + "B" + ComponentPathDivider + "C"</code>. | ||
/// </example> | ||
public static char ComponentPathDivider = '/'; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// 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 Newtonsoft.Json; | ||
|
||
namespace NuGet.Services.Status | ||
{ | ||
public class Event : IEvent | ||
{ | ||
public string AffectedComponentPath { get; } | ||
public ComponentStatus AffectedComponentStatus { get; } | ||
public DateTime StartTime { get; } | ||
public DateTime? EndTime { get; } | ||
public IEnumerable<IMessage> Messages { get; } | ||
|
||
public Event( | ||
string affectedComponentPath, | ||
ComponentStatus affectedComponentStatus, | ||
DateTime startTime, | ||
DateTime? endTime, | ||
IEnumerable<IMessage> messages) | ||
{ | ||
AffectedComponentPath = affectedComponentPath; | ||
AffectedComponentStatus = affectedComponentStatus; | ||
StartTime = startTime; | ||
EndTime = endTime; | ||
Messages = messages; | ||
} | ||
|
||
[JsonConstructor] | ||
public Event( | ||
string affectedComponentPath, | ||
ComponentStatus affectedComponentStatus, | ||
DateTime startTime, | ||
DateTime? endTime, | ||
IEnumerable<Message> messages) | ||
: this( | ||
affectedComponentPath, | ||
affectedComponentStatus, | ||
startTime, | ||
endTime, | ||
(IEnumerable<IMessage>)messages) | ||
{ | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// 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; | ||
|
||
namespace NuGet.Services.Status | ||
{ | ||
/// <summary> | ||
/// A writable <see cref="IReadOnlyComponent"/> that allows setting its status. | ||
/// </summary> | ||
public interface IComponent : IReadOnlyComponent | ||
{ | ||
new ComponentStatus Status { get; set; } | ||
new IEnumerable<IComponent> SubComponents { get; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll remove this, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I forgot that this needs to exist so that |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// 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; | ||
|
||
namespace NuGet.Services.Status | ||
{ | ||
/// <summary> | ||
/// Represents an event affecting a <see cref="IReadOnlyComponent"/>. | ||
/// </summary> | ||
public interface IEvent | ||
{ | ||
/// <summary> | ||
/// The <see cref="IReadOnlyComponent.Path"/> of the <see cref="IReadOnlyComponent"/> affected. | ||
/// </summary> | ||
string AffectedComponentPath { get; } | ||
/// <summary> | ||
/// The <see cref="IReadOnlyComponent.Status"/> of the <see cref="IReadOnlyComponent"/> affected. | ||
/// </summary> | ||
ComponentStatus AffectedComponentStatus { get; } | ||
/// <summary> | ||
/// When the event began. | ||
/// </summary> | ||
DateTime StartTime { get; } | ||
/// <summary> | ||
/// When the event ended, or <c>null</c> if the event is still active. | ||
/// </summary> | ||
DateTime? EndTime { get; } | ||
/// <summary> | ||
/// A set of <see cref="IMessage"/>s related to this event. | ||
/// </summary> | ||
IEnumerable<IMessage> Messages { get; } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// 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; | ||
|
||
namespace NuGet.Services.Status | ||
{ | ||
/// <summary> | ||
/// A message associated with an <see cref="IEvent"/>. | ||
/// </summary> | ||
public interface IMessage | ||
{ | ||
/// <summary> | ||
/// The time the message was posted. | ||
/// </summary> | ||
DateTime Time { get; } | ||
/// <summary> | ||
/// The contents of the message. | ||
/// </summary> | ||
string Contents { get; } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// 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; | ||
|
||
namespace NuGet.Services.Status | ||
{ | ||
/// <summary> | ||
/// Represents a part of the service that has a status. | ||
/// </summary> | ||
public interface IReadOnlyComponent | ||
{ | ||
/// <summary> | ||
/// The name of the part of the service. | ||
/// </summary> | ||
string Name { get; } | ||
/// <summary> | ||
/// A description of what the part of the service does. | ||
/// </summary> | ||
string Description { get; } | ||
/// <summary> | ||
/// The status of the part of the service. | ||
/// </summary> | ||
ComponentStatus Status { get; } | ||
/// <summary> | ||
/// A list of subcomponents that make up this part of the service. | ||
/// </summary> | ||
IEnumerable<IReadOnlyComponent> SubComponents { get; } | ||
/// <summary> | ||
/// A string path used to identify this part of the service when accessed by a root component. | ||
/// For example, if "A" is a component with a subcomponent "B", the path of "B" is "A/B". | ||
/// </summary> | ||
string Path { get; } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// 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. | ||
|
||
namespace NuGet.Services.Status | ||
{ | ||
/// <summary> | ||
/// A <see cref="Component"/> that has no children. | ||
/// </summary> | ||
public class LeafComponent : Component | ||
{ | ||
public override ComponentStatus Status { get; set; } | ||
|
||
public LeafComponent( | ||
string name, | ||
string description) | ||
: base(name, description) | ||
{ | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't you update
test.ps1
too?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!