This repository has been archived by the owner on Jul 30, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e4131d3
commit af98945
Showing
17 changed files
with
281 additions
and
7 deletions.
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
src/NuGet.Services.Revalidate/Configuration/HealthConfiguration.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// 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.Revalidate | ||
{ | ||
public class HealthConfiguration | ||
{ | ||
/// <summary> | ||
/// The name of the Azure Blob Storage container that stores status information. | ||
/// </summary> | ||
public string ContainerName { get; set; } | ||
|
||
/// <summary> | ||
/// The name of the Azure Blob Storage blob that stores status information. | ||
/// </summary> | ||
public string StatusBlobName { get; set; } | ||
|
||
/// <summary> | ||
/// The path to the component that the revalidation job will monitor. The revalidation job will | ||
/// pause if this component isn't healthy. | ||
/// </summary> | ||
public string ComponentPath { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,52 @@ | ||
// 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.IO; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.Logging; | ||
using Newtonsoft.Json; | ||
using NuGet.Services.Status; | ||
using NuGetGallery; | ||
|
||
namespace NuGet.Services.Revalidate | ||
{ | ||
public class HealthService : IHealthService | ||
{ | ||
public Task<bool> IsHealthyAsync() | ||
private readonly ICoreFileStorageService _storage; | ||
private readonly HealthConfiguration _config; | ||
private readonly ILogger<HealthService> _logger; | ||
|
||
public HealthService( | ||
ICoreFileStorageService storage, | ||
HealthConfiguration config, | ||
ILogger<HealthService> logger) | ||
{ | ||
_storage = storage ?? throw new ArgumentNullException(nameof(storage)); | ||
_config = config ?? throw new ArgumentNullException(nameof(config)); | ||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | ||
} | ||
|
||
public async Task<bool> IsHealthyAsync() | ||
{ | ||
// TODO: | ||
// We are software gods that never make mistakes. | ||
return Task.FromResult(true); | ||
using (var stream = await _storage.GetFileAsync(_config.ContainerName, _config.StatusBlobName)) | ||
using (var reader = new StreamReader(stream)) | ||
{ | ||
var json = await reader.ReadToEndAsync(); | ||
var status = JsonConvert.DeserializeObject<ServiceStatus>(json); | ||
var component = status.ServiceRootComponent.GetByPath(_config.ComponentPath); | ||
|
||
if (component == null) | ||
{ | ||
_logger.LogError( | ||
"Assuming that the service is unhealthy as the component path {ComponentPath} could not be found", | ||
_config.ComponentPath); | ||
|
||
return false; | ||
} | ||
|
||
return component.Status == ComponentStatus.Up; | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
tests/NuGet.Services.Revalidate.Tests/Services/HealthServiceFacts.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// 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.Threading.Tasks; | ||
using Microsoft.Extensions.Logging; | ||
using Moq; | ||
using NuGet.Services.Revalidate.Tests.TestData; | ||
using NuGetGallery; | ||
using Xunit; | ||
|
||
namespace NuGet.Services.Revalidate.Tests.Services | ||
{ | ||
public class HealthServiceFacts | ||
{ | ||
private readonly Mock<ICoreFileStorageService> _storage; | ||
private readonly HealthConfiguration _config; | ||
private readonly HealthService _target; | ||
|
||
public HealthServiceFacts() | ||
{ | ||
_storage = new Mock<ICoreFileStorageService>(); | ||
_config = new HealthConfiguration | ||
{ | ||
ContainerName = "status", | ||
StatusBlobName = "status.json", | ||
ComponentPath = "NuGet/Package Publishing" | ||
}; | ||
|
||
_target = new HealthService(_storage.Object, _config, Mock.Of<ILogger<HealthService>>()); | ||
} | ||
|
||
[Theory] | ||
[InlineData(TestResources.PackagePublishingDegradedStatus, false)] | ||
[InlineData(TestResources.PackagePublishingDownStatus, false)] | ||
[InlineData(TestResources.PackagePublishingUpStatus, true)] | ||
public async Task ReturnsHealthyIfStatusBlobIndicatesHealthyComponent(string resourceName, bool expectsHealthy) | ||
{ | ||
_storage | ||
.Setup(s => s.GetFileAsync(_config.ContainerName, _config.StatusBlobName)) | ||
.ReturnsAsync(TestResources.GetResourceStream(resourceName)); | ||
|
||
Assert.Equal(expectsHealthy, await _target.IsHealthyAsync()); | ||
} | ||
|
||
[Fact] | ||
public async Task AssumesUnhealthyIfComponentCannotBeFoundInStatusBlob() | ||
{ | ||
_storage | ||
.Setup(s => s.GetFileAsync(_config.ContainerName, _config.StatusBlobName)) | ||
.ReturnsAsync(TestResources.GetResourceStream(TestResources.PackagePublishingMissingStatus)); | ||
|
||
Assert.False(await _target.IsHealthyAsync()); | ||
} | ||
|
||
[Fact] | ||
public async Task ThrowsIfStorageServiceThrows() | ||
{ | ||
// This may happen if the status blob can't be found. | ||
var expectedException = new Exception("Look ma, I'm an exception!"); | ||
|
||
_storage | ||
.Setup(s => s.GetFileAsync(_config.ContainerName, _config.StatusBlobName)) | ||
.ThrowsAsync(expectedException); | ||
|
||
// Act & Assert | ||
var actualException = await Assert.ThrowsAsync<Exception>(() => _target.IsHealthyAsync()); | ||
|
||
Assert.Same(expectedException, actualException); | ||
} | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
tests/NuGet.Services.Revalidate.Tests/TestData/PackagePublishingDegradedStatus.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"LastUpdated": "2018-01-01T12:00:00.0000000Z", | ||
"ServiceRootComponent": { | ||
"Name": "NuGet", | ||
"Status": "Up", | ||
"SubComponents": [ | ||
{ | ||
"Status": "Degraded", | ||
"Name": "Package Publishing", | ||
"Description": "Uploading new packages to NuGet.org", | ||
"Path": "NuGet/Package Publishing" | ||
} | ||
] | ||
|
||
}, | ||
"Events": [] | ||
} |
16 changes: 16 additions & 0 deletions
16
tests/NuGet.Services.Revalidate.Tests/TestData/PackagePublishingDownStatus.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"LastUpdated": "2018-01-01T12:00:00.0000000Z", | ||
"ServiceRootComponent": { | ||
"Name": "NuGet", | ||
"Status": "Up", | ||
"SubComponents": [ | ||
{ | ||
"Status": "Down", | ||
"Name": "Package Publishing", | ||
"Description": "Uploading new packages to NuGet.org", | ||
"Path": "NuGet/Package Publishing" | ||
} | ||
] | ||
}, | ||
"Events": [] | ||
} |
16 changes: 16 additions & 0 deletions
16
tests/NuGet.Services.Revalidate.Tests/TestData/PackagePublishingMissingStatus.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"LastUpdated": "2018-01-01T12:00:00.0000000Z", | ||
"ServiceRootComponent": { | ||
"Name": "NuGet", | ||
"Status": "Up", | ||
"SubComponents": [ | ||
{ | ||
"Status": "Up", | ||
"Name": "Not Package Publishing", | ||
"Description": "Uploading new packages to NuGet.org", | ||
"Path": "NuGet/Not Package Publishing" | ||
} | ||
] | ||
}, | ||
"Events": [] | ||
} |
16 changes: 16 additions & 0 deletions
16
tests/NuGet.Services.Revalidate.Tests/TestData/PackagePublishingUpStatus.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"LastUpdated": "2018-01-01T12:00:00.0000000Z", | ||
"ServiceRootComponent": { | ||
"Name": "NuGet", | ||
"Status": "Up", | ||
"SubComponents": [ | ||
{ | ||
"Status": "Up", | ||
"Name": "Package Publishing", | ||
"Description": "Uploading new packages to NuGet.org", | ||
"Path": "NuGet/Package Publishing" | ||
} | ||
] | ||
}, | ||
"Events": [] | ||
} |
42 changes: 42 additions & 0 deletions
42
tests/NuGet.Services.Revalidate.Tests/TestData/TestResources.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// 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.IO; | ||
|
||
namespace NuGet.Services.Revalidate.Tests.TestData | ||
{ | ||
internal class TestResources | ||
{ | ||
private const string ResourceNamespace = "NuGet.Services.Revalidate.Tests.TestData"; | ||
|
||
public const string PackagePublishingDegradedStatus = ResourceNamespace + ".PackagePublishingDegradedStatus.json"; | ||
public const string PackagePublishingDownStatus = ResourceNamespace + ".PackagePublishingDownStatus.json"; | ||
public const string PackagePublishingUpStatus = ResourceNamespace + ".PackagePublishingUpStatus.json"; | ||
|
||
public const string PackagePublishingMissingStatus = ResourceNamespace + ".PackagePublishingMissingStatus.json"; | ||
|
||
/// <summary> | ||
/// Buffer the resource stream into memory so the caller doesn't have to dispose. | ||
/// </summary> | ||
public static MemoryStream GetResourceStream(string resourceName) | ||
{ | ||
var resourceStream = typeof(TestResources) | ||
.Assembly | ||
.GetManifestResourceStream(resourceName); | ||
|
||
if (resourceStream == null) | ||
{ | ||
return null; | ||
} | ||
|
||
var bufferedStream = new MemoryStream(); | ||
using (resourceStream) | ||
{ | ||
resourceStream.CopyTo(bufferedStream); | ||
} | ||
|
||
bufferedStream.Position = 0; | ||
return bufferedStream; | ||
} | ||
} | ||
} |