Skip to content

Commit fa13630

Browse files
Add unit tests for announcement and auth functions (#249)
Co-authored-by: Cursor Agent <[email protected]>
1 parent 3a497b5 commit fa13630

File tree

5 files changed

+690
-15
lines changed

5 files changed

+690
-15
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System.Net;
2+
using ByteSync.Common.Business.Announcements;
3+
using ByteSync.Functions.Http;
4+
using ByteSync.Functions.UnitTests.TestHelpers;
5+
using ByteSync.ServerCommon.Commands.Announcements;
6+
using FluentAssertions;
7+
using MediatR;
8+
using Microsoft.Azure.Functions.Worker;
9+
using Moq;
10+
11+
namespace ByteSync.Functions.UnitTests.Http;
12+
13+
[TestFixture]
14+
public class AnnouncementFunctionTests
15+
{
16+
[Test]
17+
public async Task GetAnnouncements_ReturnsOk_AndSendsRequest()
18+
{
19+
var mediatorMock = new Mock<IMediator>();
20+
var expectedAnnouncements = new List<Announcement>
21+
{
22+
new()
23+
{
24+
Id = "announcement-1",
25+
StartDate = DateTime.UtcNow.AddDays(-1),
26+
EndDate = DateTime.UtcNow.AddDays(7),
27+
Message = new Dictionary<string, string> { ["en"] = "Test announcement" }
28+
}
29+
};
30+
31+
mediatorMock
32+
.Setup(m => m.Send(It.IsAny<GetActiveAnnouncementsRequest>(), It.IsAny<CancellationToken>()))
33+
.ReturnsAsync(expectedAnnouncements);
34+
35+
var function = new AnnouncementFunction(mediatorMock.Object);
36+
var mockContext = new Mock<FunctionContext>();
37+
var context = mockContext.Object;
38+
var request = new FakeHttpRequestData(context);
39+
40+
var response = await function.GetAnnouncements(request, context);
41+
42+
response.StatusCode.Should().Be(HttpStatusCode.OK);
43+
mediatorMock.Verify(m => m.Send(It.IsAny<GetActiveAnnouncementsRequest>(), It.IsAny<CancellationToken>()), Times.Once);
44+
}
45+
46+
[Test]
47+
public async Task GetAnnouncements_ReturnsEmptyList_WhenNoAnnouncements()
48+
{
49+
var mediatorMock = new Mock<IMediator>();
50+
var emptyAnnouncements = new List<Announcement>();
51+
52+
mediatorMock
53+
.Setup(m => m.Send(It.IsAny<GetActiveAnnouncementsRequest>(), It.IsAny<CancellationToken>()))
54+
.ReturnsAsync(emptyAnnouncements);
55+
56+
var function = new AnnouncementFunction(mediatorMock.Object);
57+
var mockContext = new Mock<FunctionContext>();
58+
var context = mockContext.Object;
59+
var request = new FakeHttpRequestData(context);
60+
61+
var response = await function.GetAnnouncements(request, context);
62+
63+
response.StatusCode.Should().Be(HttpStatusCode.OK);
64+
mediatorMock.Verify(m => m.Send(It.IsAny<GetActiveAnnouncementsRequest>(), It.IsAny<CancellationToken>()), Times.Once);
65+
}
66+
}
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
using System.Net;
2+
using System.Text;
3+
using ByteSync.Common.Business.Auth;
4+
using ByteSync.Common.Business.Misc;
5+
using ByteSync.Common.Controls.Json;
6+
using ByteSync.Functions.Http;
7+
using ByteSync.Functions.UnitTests.TestHelpers;
8+
using ByteSync.ServerCommon.Commands.Authentication;
9+
using FluentAssertions;
10+
using MediatR;
11+
using Microsoft.Azure.Functions.Worker;
12+
using Moq;
13+
14+
namespace ByteSync.Functions.UnitTests.Http;
15+
16+
[TestFixture]
17+
public class AuthFunctionTests
18+
{
19+
[Test]
20+
public async Task Login_WithValidCredentials_ReturnsOk()
21+
{
22+
var mediatorMock = new Mock<IMediator>();
23+
var loginData = new LoginData
24+
{
25+
ClientId = "test-client",
26+
ClientInstanceId = "test-instance",
27+
Version = "1.0.0",
28+
OsPlatform = OSPlatforms.Windows
29+
};
30+
31+
var authResponse = new InitialAuthenticationResponse(InitialConnectionStatus.Success)
32+
{
33+
AuthenticationTokens = new AuthenticationTokens
34+
{
35+
JwtToken = "test-jwt-token",
36+
RefreshToken = "test-refresh-token",
37+
JwtTokenDurationInSeconds = 3600,
38+
RefreshTokenExpiration = DateTimeOffset.UtcNow.AddDays(30)
39+
}
40+
};
41+
42+
AuthenticateRequest? captured = null;
43+
mediatorMock
44+
.Setup(m => m.Send(It.IsAny<AuthenticateRequest>(), It.IsAny<CancellationToken>()))
45+
.Callback<object, CancellationToken>((r, _) => captured = (AuthenticateRequest)r)
46+
.ReturnsAsync(authResponse);
47+
48+
var function = new AuthFunction(mediatorMock.Object);
49+
var mockContext = new Mock<FunctionContext>();
50+
var context = mockContext.Object;
51+
var request = new FakeHttpRequestData(context);
52+
request.Headers.Add("x-forwarded-for", "192.168.1.1");
53+
54+
var json = JsonHelper.Serialize(loginData);
55+
await using (var writer = new StreamWriter(request.Body, Encoding.UTF8, 1024, leaveOpen: true))
56+
{
57+
await writer.WriteAsync(json);
58+
}
59+
request.Body.Position = 0;
60+
61+
var response = await function.Login(request, context);
62+
63+
response.StatusCode.Should().Be(HttpStatusCode.OK);
64+
captured.Should().NotBeNull();
65+
captured!.LoginData.Should().NotBeNull();
66+
captured.LoginData.ClientId.Should().Be("test-client");
67+
captured.LoginData.ClientInstanceId.Should().Be("test-instance");
68+
captured.IpAddress.Should().Be("192.168.1.1");
69+
}
70+
71+
[Test]
72+
public async Task Login_WithInvalidCredentials_ReturnsUnauthorized()
73+
{
74+
var mediatorMock = new Mock<IMediator>();
75+
var loginData = new LoginData
76+
{
77+
ClientId = "invalid-client",
78+
ClientInstanceId = "test-instance",
79+
Version = "1.0.0",
80+
OsPlatform = OSPlatforms.Windows
81+
};
82+
83+
var authResponse = new InitialAuthenticationResponse(InitialConnectionStatus.UndefinedClientId);
84+
85+
mediatorMock
86+
.Setup(m => m.Send(It.IsAny<AuthenticateRequest>(), It.IsAny<CancellationToken>()))
87+
.ReturnsAsync(authResponse);
88+
89+
var function = new AuthFunction(mediatorMock.Object);
90+
var mockContext = new Mock<FunctionContext>();
91+
var context = mockContext.Object;
92+
var request = new FakeHttpRequestData(context);
93+
request.Headers.Add("x-forwarded-for", "192.168.1.1");
94+
95+
var json = JsonHelper.Serialize(loginData);
96+
await using (var writer = new StreamWriter(request.Body, Encoding.UTF8, 1024, leaveOpen: true))
97+
{
98+
await writer.WriteAsync(json);
99+
}
100+
request.Body.Position = 0;
101+
102+
var response = await function.Login(request, context);
103+
104+
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
105+
mediatorMock.Verify(m => m.Send(It.IsAny<AuthenticateRequest>(), It.IsAny<CancellationToken>()), Times.Once);
106+
}
107+
108+
[Test]
109+
public async Task RefreshTokens_WithValidToken_ReturnsOk()
110+
{
111+
var mediatorMock = new Mock<IMediator>();
112+
var refreshTokensData = new RefreshTokensData
113+
{
114+
Token = "valid-refresh-token",
115+
ClientInstanceId = "test-instance",
116+
Version = "1.0.0",
117+
OsPlatform = OSPlatforms.Windows
118+
};
119+
120+
var refreshResponse = new RefreshTokensResponse(RefreshTokensStatus.RefreshTokenOk, new AuthenticationTokens
121+
{
122+
JwtToken = "new-jwt-token",
123+
RefreshToken = "new-refresh-token",
124+
JwtTokenDurationInSeconds = 3600,
125+
RefreshTokenExpiration = DateTimeOffset.UtcNow.AddDays(30)
126+
});
127+
128+
RefreshTokensRequest? captured = null;
129+
mediatorMock
130+
.Setup(m => m.Send(It.IsAny<RefreshTokensRequest>(), It.IsAny<CancellationToken>()))
131+
.Callback<object, CancellationToken>((r, _) => captured = (RefreshTokensRequest)r)
132+
.ReturnsAsync(refreshResponse);
133+
134+
var function = new AuthFunction(mediatorMock.Object);
135+
var mockContext = new Mock<FunctionContext>();
136+
var context = mockContext.Object;
137+
var request = new FakeHttpRequestData(context);
138+
request.Headers.Add("x-forwarded-for", "10.0.0.1");
139+
140+
var json = JsonHelper.Serialize(refreshTokensData);
141+
await using (var writer = new StreamWriter(request.Body, Encoding.UTF8, 1024, leaveOpen: true))
142+
{
143+
await writer.WriteAsync(json);
144+
}
145+
request.Body.Position = 0;
146+
147+
var response = await function.RefreshTokens(request, context);
148+
149+
response.StatusCode.Should().Be(HttpStatusCode.OK);
150+
captured.Should().NotBeNull();
151+
captured!.RefreshTokensData.Should().NotBeNull();
152+
captured.RefreshTokensData.Token.Should().Be("valid-refresh-token");
153+
captured.RefreshTokensData.ClientInstanceId.Should().Be("test-instance");
154+
captured.IpAddress.Should().Be("10.0.0.1");
155+
}
156+
157+
[Test]
158+
public async Task RefreshTokens_WithInvalidToken_ReturnsUnauthorized()
159+
{
160+
var mediatorMock = new Mock<IMediator>();
161+
var refreshTokensData = new RefreshTokensData
162+
{
163+
Token = "invalid-refresh-token",
164+
ClientInstanceId = "test-instance",
165+
Version = "1.0.0",
166+
OsPlatform = OSPlatforms.Windows
167+
};
168+
169+
var refreshResponse = new RefreshTokensResponse(RefreshTokensStatus.RefreshTokenNotFound);
170+
171+
mediatorMock
172+
.Setup(m => m.Send(It.IsAny<RefreshTokensRequest>(), It.IsAny<CancellationToken>()))
173+
.ReturnsAsync(refreshResponse);
174+
175+
var function = new AuthFunction(mediatorMock.Object);
176+
var mockContext = new Mock<FunctionContext>();
177+
var context = mockContext.Object;
178+
var request = new FakeHttpRequestData(context);
179+
request.Headers.Add("x-forwarded-for", "10.0.0.1");
180+
181+
var json = JsonHelper.Serialize(refreshTokensData);
182+
await using (var writer = new StreamWriter(request.Body, Encoding.UTF8, 1024, leaveOpen: true))
183+
{
184+
await writer.WriteAsync(json);
185+
}
186+
request.Body.Position = 0;
187+
188+
var response = await function.RefreshTokens(request, context);
189+
190+
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
191+
mediatorMock.Verify(m => m.Send(It.IsAny<RefreshTokensRequest>(), It.IsAny<CancellationToken>()), Times.Once);
192+
}
193+
}

0 commit comments

Comments
 (0)