Skip to content

Commit 23f5d31

Browse files
committed
[2.x] Added IsHealthy() method on HttpGateway
inertiajs/inertia-laravel#752
1 parent 8c4c929 commit 23f5d31

File tree

3 files changed

+198
-1
lines changed

3 files changed

+198
-1
lines changed

InertiaCore/Ssr/Gateway.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
namespace InertiaCore.Ssr;
1010

11-
internal interface IGateway
11+
internal interface IGateway : IHasHealthCheck
1212
{
1313
public Task<SsrResponse?> Dispatch(object model, string url);
1414
public bool ShouldDispatch();
@@ -75,4 +75,26 @@ private bool BundleExists()
7575
}
7676
return Path.IsPathRooted(path) ? path : Path.Combine(_environment.ContentRootPath, path);
7777
}
78+
79+
public async Task<bool> IsHealthy()
80+
{
81+
try
82+
{
83+
var healthUrl = GetUrl("/health");
84+
var client = _httpClientFactory.CreateClient();
85+
86+
using var response = await client.GetAsync(healthUrl);
87+
return response.IsSuccessStatusCode;
88+
}
89+
catch
90+
{
91+
return false;
92+
}
93+
}
94+
95+
private string GetUrl(string endpoint)
96+
{
97+
var baseUrl = _options.Value.SsrUrl.TrimEnd('/');
98+
return $"{baseUrl}{endpoint}";
99+
}
78100
}

InertiaCore/Ssr/IHasHealthCheck.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace InertiaCore.Ssr;
2+
3+
internal interface IHasHealthCheck
4+
{
5+
public Task<bool> IsHealthy();
6+
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
using System.Net;
2+
using InertiaCore.Models;
3+
using InertiaCore.Ssr;
4+
using Microsoft.AspNetCore.Hosting;
5+
using Microsoft.Extensions.Options;
6+
using Moq;
7+
using Moq.Protected;
8+
9+
namespace InertiaCoreTests;
10+
11+
public partial class Tests
12+
{
13+
[Test]
14+
[Description("Test SSR health check returns true when server responds with success")]
15+
public async Task TestSsrHealthCheckReturnsTrue()
16+
{
17+
var httpMessageHandlerMock = new Mock<HttpMessageHandler>();
18+
httpMessageHandlerMock
19+
.Protected()
20+
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
21+
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));
22+
23+
var httpClient = new HttpClient(httpMessageHandlerMock.Object);
24+
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
25+
httpClientFactoryMock.Setup(f => f.CreateClient(It.IsAny<string>())).Returns(httpClient);
26+
27+
var environment = new Mock<IWebHostEnvironment>();
28+
environment.SetupGet(x => x.ContentRootPath).Returns(Path.GetTempPath());
29+
30+
var options = new Mock<IOptions<InertiaOptions>>();
31+
options.SetupGet(x => x.Value).Returns(new InertiaOptions { SsrUrl = "http://localhost:13714" });
32+
33+
var gateway = new Gateway(httpClientFactoryMock.Object, options.Object, environment.Object);
34+
35+
var result = await gateway.IsHealthy();
36+
37+
Assert.That(result, Is.True);
38+
httpMessageHandlerMock.Protected().Verify(
39+
"SendAsync",
40+
Times.Once(),
41+
ItExpr.Is<HttpRequestMessage>(req =>
42+
req.Method == HttpMethod.Get &&
43+
req.RequestUri!.ToString() == "http://localhost:13714/health"),
44+
ItExpr.IsAny<CancellationToken>()
45+
);
46+
}
47+
48+
[Test]
49+
[Description("Test SSR health check returns false when server responds with error")]
50+
public async Task TestSsrHealthCheckReturnsFalseOnError()
51+
{
52+
var httpMessageHandlerMock = new Mock<HttpMessageHandler>();
53+
httpMessageHandlerMock
54+
.Protected()
55+
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
56+
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.InternalServerError));
57+
58+
var httpClient = new HttpClient(httpMessageHandlerMock.Object);
59+
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
60+
httpClientFactoryMock.Setup(f => f.CreateClient(It.IsAny<string>())).Returns(httpClient);
61+
62+
var environment = new Mock<IWebHostEnvironment>();
63+
environment.SetupGet(x => x.ContentRootPath).Returns(Path.GetTempPath());
64+
65+
var options = new Mock<IOptions<InertiaOptions>>();
66+
options.SetupGet(x => x.Value).Returns(new InertiaOptions { SsrUrl = "http://localhost:13714" });
67+
68+
var gateway = new Gateway(httpClientFactoryMock.Object, options.Object, environment.Object);
69+
70+
var result = await gateway.IsHealthy();
71+
72+
Assert.That(result, Is.False);
73+
}
74+
75+
[Test]
76+
[Description("Test SSR health check returns false when request throws exception")]
77+
public async Task TestSsrHealthCheckReturnsFalseOnException()
78+
{
79+
var httpMessageHandlerMock = new Mock<HttpMessageHandler>();
80+
httpMessageHandlerMock
81+
.Protected()
82+
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
83+
.ThrowsAsync(new HttpRequestException("Connection failed"));
84+
85+
var httpClient = new HttpClient(httpMessageHandlerMock.Object);
86+
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
87+
httpClientFactoryMock.Setup(f => f.CreateClient(It.IsAny<string>())).Returns(httpClient);
88+
89+
var environment = new Mock<IWebHostEnvironment>();
90+
environment.SetupGet(x => x.ContentRootPath).Returns(Path.GetTempPath());
91+
92+
var options = new Mock<IOptions<InertiaOptions>>();
93+
options.SetupGet(x => x.Value).Returns(new InertiaOptions { SsrUrl = "http://localhost:13714" });
94+
95+
var gateway = new Gateway(httpClientFactoryMock.Object, options.Object, environment.Object);
96+
97+
var result = await gateway.IsHealthy();
98+
99+
Assert.That(result, Is.False);
100+
}
101+
102+
[Test]
103+
[Description("Test SSR health check constructs correct URL with trailing slash")]
104+
public async Task TestSsrHealthCheckUrlWithTrailingSlash()
105+
{
106+
var httpMessageHandlerMock = new Mock<HttpMessageHandler>();
107+
httpMessageHandlerMock
108+
.Protected()
109+
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
110+
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));
111+
112+
var httpClient = new HttpClient(httpMessageHandlerMock.Object);
113+
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
114+
httpClientFactoryMock.Setup(f => f.CreateClient(It.IsAny<string>())).Returns(httpClient);
115+
116+
var environment = new Mock<IWebHostEnvironment>();
117+
environment.SetupGet(x => x.ContentRootPath).Returns(Path.GetTempPath());
118+
119+
var options = new Mock<IOptions<InertiaOptions>>();
120+
options.SetupGet(x => x.Value).Returns(new InertiaOptions { SsrUrl = "http://localhost:13714/" });
121+
122+
var gateway = new Gateway(httpClientFactoryMock.Object, options.Object, environment.Object);
123+
124+
await gateway.IsHealthy();
125+
126+
httpMessageHandlerMock.Protected().Verify(
127+
"SendAsync",
128+
Times.Once(),
129+
ItExpr.Is<HttpRequestMessage>(req =>
130+
req.Method == HttpMethod.Get &&
131+
req.RequestUri!.ToString() == "http://localhost:13714/health"),
132+
ItExpr.IsAny<CancellationToken>()
133+
);
134+
}
135+
136+
[Test]
137+
[Description("Test SSR health check works with different port")]
138+
public async Task TestSsrHealthCheckWithDifferentPort()
139+
{
140+
var httpMessageHandlerMock = new Mock<HttpMessageHandler>();
141+
httpMessageHandlerMock
142+
.Protected()
143+
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
144+
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));
145+
146+
var httpClient = new HttpClient(httpMessageHandlerMock.Object);
147+
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
148+
httpClientFactoryMock.Setup(f => f.CreateClient(It.IsAny<string>())).Returns(httpClient);
149+
150+
var environment = new Mock<IWebHostEnvironment>();
151+
environment.SetupGet(x => x.ContentRootPath).Returns(Path.GetTempPath());
152+
153+
var options = new Mock<IOptions<InertiaOptions>>();
154+
options.SetupGet(x => x.Value).Returns(new InertiaOptions { SsrUrl = "http://127.0.0.1:8080/ssr" });
155+
156+
var gateway = new Gateway(httpClientFactoryMock.Object, options.Object, environment.Object);
157+
158+
await gateway.IsHealthy();
159+
160+
httpMessageHandlerMock.Protected().Verify(
161+
"SendAsync",
162+
Times.Once(),
163+
ItExpr.Is<HttpRequestMessage>(req =>
164+
req.Method == HttpMethod.Get &&
165+
req.RequestUri!.ToString() == "http://127.0.0.1:8080/ssr/health"),
166+
ItExpr.IsAny<CancellationToken>()
167+
);
168+
}
169+
}

0 commit comments

Comments
 (0)