-
Notifications
You must be signed in to change notification settings - Fork 166
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'stu3/master' into r4/master
- Loading branch information
Showing
32 changed files
with
904 additions
and
75 deletions.
There are no files selected for viewing
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
133 changes: 133 additions & 0 deletions
133
src/Spark.Engine.Test/Maintenance/MaintenanceModeTests.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,133 @@ | ||
using Spark.Engine.Maintenance; | ||
using System.Linq; | ||
using System.Net; | ||
using Xunit; | ||
|
||
namespace Spark.Engine.Test.Maintenance | ||
{ | ||
public class MaintenanceModeTests | ||
{ | ||
[Theory] | ||
[MemberData(nameof(AllLockModes))] | ||
internal void IsEnabled_Should_Return_False_If_Maintenance_Mode_Is_Not_Enabled(MaintenanceLockMode mode) | ||
{ | ||
Assert.False(MaintenanceMode.IsEnabled(mode)); | ||
} | ||
|
||
[Theory] | ||
[MemberData(nameof(AllLockModes))] | ||
internal void IsEnabled_Should_Not_Lock_If_Lock_None_Is_Provided(MaintenanceLockMode mode) | ||
{ | ||
using (MaintenanceMode.Enable(MaintenanceLockMode.None)) | ||
{ | ||
Assert.False(MaintenanceMode.IsEnabled(mode)); | ||
} | ||
} | ||
|
||
[Fact] | ||
internal void IsEnabled_Should_Not_Lock_Read_If_Write_Only_Mock_Mode_Is_Provided() | ||
{ | ||
using (MaintenanceMode.Enable(MaintenanceLockMode.Write)) | ||
{ | ||
Assert.True(MaintenanceMode.IsEnabled(MaintenanceLockMode.None)); | ||
Assert.True(MaintenanceMode.IsEnabled(MaintenanceLockMode.Write)); | ||
Assert.False(MaintenanceMode.IsEnabled(MaintenanceLockMode.Full)); | ||
} | ||
} | ||
|
||
[Fact] | ||
internal void IsEnabled_Full_Lock_Mode_Should_Lock_Read_And_Write() | ||
{ | ||
using (MaintenanceMode.Enable(MaintenanceLockMode.Full)) | ||
{ | ||
Assert.True(MaintenanceMode.IsEnabled(MaintenanceLockMode.None)); | ||
Assert.True(MaintenanceMode.IsEnabled(MaintenanceLockMode.Write)); | ||
Assert.True(MaintenanceMode.IsEnabled(MaintenanceLockMode.Full)); | ||
} | ||
} | ||
|
||
[Theory] | ||
[MemberData(nameof(ActualLockModes))] | ||
internal void Should_Not_Allow_To_Lock_Twice(MaintenanceLockMode mode) | ||
{ | ||
using (MaintenanceMode.Enable(mode)) | ||
{ | ||
var e = Assert.Throws<MaintenanceModeEnabledException>(() => MaintenanceMode.Enable(mode)); | ||
Assert.Equal(HttpStatusCode.ServiceUnavailable, e.StatusCode); | ||
} | ||
} | ||
|
||
[Theory] | ||
[MemberData(nameof(AllHttpMethods))] | ||
internal void IsEnabledForHttpMethod_Should_Return_False_If_Maintenance_Mode_Is_Not_Enabled(string method) | ||
{ | ||
Assert.False(MaintenanceMode.IsEnabledForHttpMethod(method)); | ||
} | ||
|
||
[Theory] | ||
[MemberData(nameof(ReadHttpMethods))] | ||
internal void IsEnabledForHttpMethod_Should_Return_False_For_Read_Methods_Write_Only_Lock(string method) | ||
{ | ||
using (MaintenanceMode.Enable(MaintenanceLockMode.Write)) | ||
{ | ||
Assert.False(MaintenanceMode.IsEnabledForHttpMethod(method)); | ||
} | ||
} | ||
|
||
[Theory] | ||
[MemberData(nameof(ReadHttpMethods))] | ||
internal void IsEnabledForHttpMethod_Should_Return_True_For_Read_Methods_Full_Lock(string method) | ||
{ | ||
using (MaintenanceMode.Enable(MaintenanceLockMode.Full)) | ||
{ | ||
Assert.True(MaintenanceMode.IsEnabledForHttpMethod(method)); | ||
} | ||
} | ||
|
||
[Theory] | ||
[MemberData(nameof(WriteHttpMethods))] | ||
internal void IsEnabledForHttpMethod_Should_Return_True_For_Update_Methods_Write_Only_Lock(string method) | ||
{ | ||
using (MaintenanceMode.Enable(MaintenanceLockMode.Write)) | ||
{ | ||
Assert.True(MaintenanceMode.IsEnabledForHttpMethod(method)); | ||
} | ||
} | ||
|
||
[Theory] | ||
[MemberData(nameof(WriteHttpMethods))] | ||
internal void IsEnabledForHttpMethod_Should_Return_True_For_Update_Methods_Full_Lock(string method) | ||
{ | ||
using (MaintenanceMode.Enable(MaintenanceLockMode.Full)) | ||
{ | ||
Assert.True(MaintenanceMode.IsEnabledForHttpMethod(method)); | ||
} | ||
} | ||
|
||
public static object[][] ReadHttpMethods => new[] | ||
{ | ||
new object[] {"GET"}, | ||
new object[] {"HEAD"}, | ||
new object[] {"OPTIONS"} | ||
}; | ||
|
||
public static object[][] WriteHttpMethods => new[] | ||
{ | ||
new object[] {"POST"}, | ||
new object[] {"PUT"}, | ||
new object[] {"PATCH"}, | ||
new object[] {"DELETE"} | ||
}; | ||
|
||
public static object[][] AllHttpMethods => ReadHttpMethods.Concat(WriteHttpMethods).ToArray(); | ||
|
||
public static object[][] AllLockModes => ((MaintenanceLockMode[])typeof(MaintenanceLockMode).GetEnumValues()) | ||
.Select(v => new object[] { v }) | ||
.ToArray(); | ||
|
||
public static object[][] ActualLockModes => ((MaintenanceLockMode[])typeof(MaintenanceLockMode).GetEnumValues()) | ||
.Where(m => m != MaintenanceLockMode.None) | ||
.Select(v => new object[] { v }) | ||
.ToArray(); | ||
} | ||
} |
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 |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using System; | ||
|
||
namespace Spark.Engine.Maintenance | ||
{ | ||
internal class MaintenanceLock : IDisposable | ||
{ | ||
public MaintenanceLockMode Mode { get; private set; } | ||
|
||
public bool IsLocked => Mode > MaintenanceLockMode.None; | ||
|
||
public MaintenanceLock(MaintenanceLockMode mode) | ||
{ | ||
Mode = mode; | ||
} | ||
|
||
public void Unlock() | ||
{ | ||
Mode = MaintenanceLockMode.None; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
Unlock(); | ||
} | ||
} | ||
} |
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,9 @@ | ||
namespace Spark.Engine.Maintenance | ||
{ | ||
internal enum MaintenanceLockMode | ||
{ | ||
None = 0, | ||
Write = 1, | ||
Full = 2 | ||
} | ||
} |
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,58 @@ | ||
using System; | ||
|
||
namespace Spark.Engine.Maintenance | ||
{ | ||
internal static class MaintenanceMode | ||
{ | ||
private static readonly object _mutex = new object(); | ||
private static volatile MaintenanceLock _lock; | ||
|
||
/// <summary> | ||
/// Whether maintenance mode is enabled. If <code>true</code> | ||
/// then all the data modifying requests should be responded | ||
/// with <code>503</code> HTTP status code. | ||
/// </summary> | ||
public static bool IsEnabled(MaintenanceLockMode mode) => _lock?.IsLocked == true && _lock.Mode >= mode; | ||
|
||
/// <summary> | ||
/// Sets maintenance mode ON. The returned lock handle should be used | ||
/// to reset the maintenance state. | ||
/// </summary> | ||
/// <param name="mode">Lock mode, write only, or read and write</param> | ||
/// <exception cref="MaintenanceModeEnabledException">Maintenance mode already enabled somewhere else.</exception> | ||
public static MaintenanceLock Enable(MaintenanceLockMode mode) | ||
{ | ||
if (_lock?.IsLocked != true) | ||
{ | ||
lock (_mutex) | ||
{ | ||
if (_lock?.IsLocked != true) | ||
{ | ||
_lock = new MaintenanceLock(mode); | ||
return _lock; | ||
} | ||
} | ||
} | ||
throw new MaintenanceModeEnabledException(); | ||
} | ||
|
||
public static bool IsEnabledForHttpMethod(string method) | ||
{ | ||
if (string.IsNullOrWhiteSpace(method)) | ||
{ | ||
throw new ArgumentException(nameof(method)); | ||
} | ||
|
||
switch (method.ToUpper()) | ||
{ | ||
case "GET": | ||
case "HEAD": | ||
case "OPTIONS": | ||
return IsEnabled(MaintenanceLockMode.Full); | ||
|
||
default: // PUT, POST, PATCH, DELETE ETC | ||
return IsEnabled(MaintenanceLockMode.Write); | ||
} | ||
} | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/Spark.Engine/Maintenance/MaintenanceModeEnabledException.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,12 @@ | ||
using Spark.Engine.Core; | ||
using System.Net; | ||
|
||
namespace Spark.Engine.Maintenance | ||
{ | ||
internal class MaintenanceModeEnabledException : SparkException | ||
{ | ||
public MaintenanceModeEnabledException() : base(HttpStatusCode.ServiceUnavailable) | ||
{ | ||
} | ||
} | ||
} |
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,27 @@ | ||
#if NETSTANDARD2_0 | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Http; | ||
|
||
namespace Spark.Engine.Maintenance | ||
{ | ||
public class MaintenanceModeHandler | ||
{ | ||
private readonly RequestDelegate _next; | ||
|
||
public MaintenanceModeHandler(RequestDelegate next) | ||
{ | ||
_next = next; | ||
} | ||
|
||
public async Task InvokeAsync(HttpContext context) | ||
{ | ||
if (MaintenanceMode.IsEnabledForHttpMethod(context.Request.Method)) | ||
{ | ||
context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable; | ||
return; | ||
} | ||
await _next(context); | ||
} | ||
} | ||
} | ||
#endif |
21 changes: 21 additions & 0 deletions
21
src/Spark.Engine/Maintenance/MaintenanceModeNetHttpHandler.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,21 @@ | ||
#if NET461 | ||
using System.Net; | ||
using System.Net.Http; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace Spark.Engine.Maintenance | ||
{ | ||
public class MaintenanceModeNetHttpHandler : DelegatingHandler | ||
{ | ||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) | ||
{ | ||
if (MaintenanceMode.IsEnabledForHttpMethod(request.Method.Method)) | ||
{ | ||
return request.CreateResponse(HttpStatusCode.ServiceUnavailable); | ||
} | ||
return await base.SendAsync(request, cancellationToken); | ||
} | ||
} | ||
} | ||
#endif |
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,11 @@ | ||
using System.Runtime.CompilerServices; | ||
|
||
[assembly: InternalsVisibleTo("Spark.Engine.Test")] | ||
|
||
namespace Spark.Engine.Properties | ||
{ | ||
|
||
internal class AssemblyInfo | ||
{ | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/Spark.Engine/Service/FhirServiceExtensions/IIndexBuildProgressReporter.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,11 @@ | ||
using System.Threading.Tasks; | ||
|
||
namespace Spark.Engine.Service.FhirServiceExtensions | ||
{ | ||
public interface IIndexBuildProgressReporter | ||
{ | ||
Task ReportProgressAsync(int progress, string message); | ||
|
||
Task ReportErrorAsync(string message); | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
src/Spark.Engine/Service/FhirServiceExtensions/IIndexRebuildService.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,9 @@ | ||
using System.Threading.Tasks; | ||
|
||
namespace Spark.Engine.Service.FhirServiceExtensions | ||
{ | ||
public interface IIndexRebuildService | ||
{ | ||
Task RebuildIndexAsync(IIndexBuildProgressReporter reporter = null); | ||
} | ||
} |
Oops, something went wrong.