Skip to content

Instantly share code, notes, and snippets.

@justinyoo
Last active August 13, 2021 17:34
Show Gist options
  • Select an option

  • Save justinyoo/c06c3b4df77d4fc6075f924e19ec0d6a to your computer and use it in GitHub Desktop.

Select an option

Save justinyoo/c06c3b4df77d4fc6075f924e19ec0d6a to your computer and use it in GitHub Desktop.
Azure Functions SRE, The First Cut
public interface IHealthCheckFunction : IFunction<ILogger>
{
}
public class HealthCheckFunction : FunctionBase<ILogger>, IHealthCheckFunction
{
...
// Dependency injections here
public override async Task<TOutput> InvokeAsync<TInput, TOutput>(
TInput input,
functionOptionsBase options = null)
{
var result = (IActionResult)null;
var requestUri = $"{this._settings.BaseUri.TrimEnd('/')}/{this._settings.Endpoints.HealthCheck.TrimStart('/')}";
using (var response = await this._httpClient.GetAsync(requestUri).ConfigureAwaitfalse))
{
try
{
response.EnsureSuccessStatusCode();
result = new OkResult();
}
catch (Exception ex)
{
var error = new ErrorResponse(ex);
result = new ObjectResult(error) { StatusCode = (int)response.StatusCode };
}
}
return (TOutput)result;
}
}
public class HealthCheckHttpTrigger
{
...
// Dependency injections here
[FunctionName(nameof(HealthCheckHttpTrigger.PingAsync))]
public async Task<IActionResult> PingAsync(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "ping")] HttpRequest req,
ILogger log)
{
return result = await this._function
.InvokeAsync<HttpRequest, IActionResult>(req)
.ConfigureAwait(false);
}
}
npm install -g mountebank
dotnet test [Test_Project_Name].csproj -c Release --filter:"TestCategory=Integration"
[TestClass]
public class HealthCheckHttpTriggerTests
{
private const string CategoryIntegration = "Integration";
private ServerFixture _fixture;
[TestInitialize]
public void Init()
{
this._fixture = new LocalhostServerFixture();
}
[TestMethod]
[TestCategory(CategoryIntegration)]
public async Task Given_Url_When_Invoked_Then_Trigger_Should_Return_Healthy()
{
// Arrange
var uri = this._fixture.GetHealthCheckUrl();
using (var http = new HttpClient())
// Act
using (var res = await http.GetAsync(uri))
{
// Assert
res.StatusCode.Should().Be(HttpStatusCode.OK);
}
}
[TestMethod]
[TestCategory(CategoryIntegration)]
public async Task Given_Url_When_Invoked_Then_Trigger_Should_Return_Unhealthy()
{
// Arrange
var uri = this._fixture.GetHealthCheckUrl(HttpStatusCode.InternalServerError);
using (var http = new HttpClient())
// Act
using (var res = await http.GetAsync(uri))
{
// Assert
res.StatusCode.Should().Be(HttpStatusCode.InternalServerError);
}
}
}
public class LocalhostServerFixture
{
private readonly MountebankClient _client;
public MountebankServerFixture()
{
this._client = new MountebankClient();
}
public override string GetHealthCheckUrl(HttpStatusCode statusCode = HttpStatusCode.OK)
{
this._client.DeleteImposter(8080);
var imposter = this._client
.CreateHttpImposter(8080, statusCode.ToString());
imposter.AddStub()
.OnPathAndMethodEqual("/api/ping", Method.Get)
.ReturnsStatus(statusCode);
this._client.Submit(imposter);
return "http://localhost:7071/api/ping";
}
}
start /b mb --noLogFile
start /b func host start --csharp
# Console #1
mb --noLogFile
# Console #2
func host start --csharp
dotnet test [Test_Project_Name].csproj -c Release
[TestMethod]
public async Task Given_Parameters_When_Invoked_Then_InvokeAsync_Should_Return_Result()
{
// Arrange
var result = new OkResult();
var function = new Mock<IHealthCheckFunction>();
function.Setup(p => p.InvokeAsync<HttpRequest, IActionResult>(It.IsAny<HttpRequest>(), It.IsAny<FunctionOptionsBase>()))
.ReturnsAsync(result);
var trigger = new HealthCheckHttpTrigger(function.Object);
var req = new Mock<HttpRequest>();
var log = new Mock<ILogger>();
// Action
var response = await trigger.PingAsync(req.Object, log.Object).ConfigureAwait(false);
// Assert
response
.Should().BeOfType<OkResult>()
.And.Subject.As<OkResult>()
.StatusCode.Should().Be((int)HttpStatusCode.OK);
}
[TestMethod]
public async Task Given_Parameters_When_Invoked_Then_InvokeAsync_Should_Return_Result()
{
// Arrange
var result = new OkResult();
var function = new Mock<IHealthCheckFunction>();
function.Setup(p => p.InvokeAsync<HttpRequest, IActionResult>(It.IsAny<HttpRequest>(), It.IsAny<FunctionOptionsBase>()))
.ReturnsAsync(result);
var trigger = new HealthCheckHttpTrigger(function.Object);
var req = new Mock<HttpRequest>();
var log = new Mock<ILogger>();
// Action
var response = await trigger.PingAsync(req.Object, log.Object).ConfigureAwait(false);
// Assert
response
.Should().BeOfType<OkResult>()
.And.Subject.As<OkResult>()
.StatusCode.Should().Be((int)HttpStatusCode.OK);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment