Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/WayfarerMobile.Core/Interfaces/IGroupsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Task<Dictionary<string, MemberLocation>> GetLatestLocationsAsync(

/// <summary>
/// Updates the current user's peer visibility setting.
/// PATCH /api/mobile/groups/{groupId}/peer-visibility
/// POST /api/mobile/groups/{groupId}/peer-visibility
/// </summary>
/// <param name="groupId">The group ID.</param>
/// <param name="disabled">Whether peer visibility should be disabled.</param>
Expand Down
2 changes: 1 addition & 1 deletion src/WayfarerMobile.Core/Models/GroupLocationModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public class GroupLocationResult

/// <summary>
/// Request to update peer visibility.
/// PATCH /api/mobile/groups/{groupId}/peer-visibility
/// POST /api/mobile/groups/{groupId}/peer-visibility
/// </summary>
public class PeerVisibilityUpdateRequest
{
Expand Down
2 changes: 1 addition & 1 deletion src/WayfarerMobile/Services/GroupsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ public async Task<bool> UpdatePeerVisibilityAsync(

try
{
var request = CreateRequest(new HttpMethod("PATCH"), $"/api/mobile/groups/{groupId}/peer-visibility");
var request = CreateRequest(HttpMethod.Post, $"/api/mobile/groups/{groupId}/peer-visibility");
request.Content = JsonContent.Create(new PeerVisibilityUpdateRequest { Disabled = disabled }, options: JsonOptions);

var response = await HttpClientInstance.SendAsync(request, cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using System.Net;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Moq.Protected;
using WayfarerMobile.Services;

namespace WayfarerMobile.Tests.Unit.Services;

/// <summary>
/// Regression tests for the production <see cref="GroupsService"/> peer-visibility request.
/// </summary>
public class ProductionGroupsServiceTests
{
[Theory]
[InlineData(true, HttpStatusCode.OK, true)]
[InlineData(false, HttpStatusCode.Forbidden, false)]
public async Task UpdatePeerVisibilityAsync_SendsOneAuthenticatedPostAndReturnsStatusResult(
bool disabled,
HttpStatusCode statusCode,
bool expectedResult)
{
var groupId = Guid.Parse("11111111-2222-3333-4444-555555555555");
HttpMethod? capturedMethod = null;
Uri? capturedUri = null;
string? capturedAuthorization = null;
string? capturedContent = null;
var contactCount = 0;
var handler = new Mock<HttpMessageHandler>();
handler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.Returns<HttpRequestMessage, CancellationToken>(async (request, token) =>
{
contactCount++;
capturedMethod = request.Method;
capturedUri = request.RequestUri;
capturedAuthorization = request.Headers.Authorization?.ToString();
capturedContent = await request.Content!.ReadAsStringAsync(token);

return new HttpResponseMessage(statusCode);
});

using var httpClient = new HttpClient(handler.Object);
var httpClientFactory = new Mock<IHttpClientFactory>();
httpClientFactory.Setup(factory => factory.CreateClient("WayfarerApi")).Returns(httpClient);
var settings = new Mock<ISettingsService>();
settings.Setup(value => value.IsConfigured).Returns(true);
settings.Setup(value => value.ServerUrl).Returns("https://api.example.com");
settings.Setup(value => value.ApiToken).Returns("test-token-123");
var service = new GroupsService(
settings.Object,
Mock.Of<ILogger<GroupsService>>(),
httpClientFactory.Object);

var result = await service.UpdatePeerVisibilityAsync(groupId, disabled);

result.Should().Be(expectedResult);
contactCount.Should().Be(1);
capturedMethod.Should().Be(HttpMethod.Post);
capturedUri.Should().Be(new Uri($"https://api.example.com/api/mobile/groups/{groupId}/peer-visibility"));
capturedAuthorization.Should().Be("Bearer test-token-123");
using var content = JsonDocument.Parse(capturedContent!);
content.RootElement.GetProperty("disabled").GetBoolean().Should().Be(disabled);
}

[Fact]
public async Task UpdatePeerVisibilityAsync_ForwardsCancellationToSendAsync()
{
var sendStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
var sendCompletion = new TaskCompletionSource<HttpResponseMessage>(
TaskCreationOptions.RunContinuationsAsynchronously);
var capturedCancellationToken = CancellationToken.None;
var handler = new Mock<HttpMessageHandler>();
handler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.Returns<HttpRequestMessage, CancellationToken>((_, token) =>
{
capturedCancellationToken = token;
sendStarted.SetResult();
return sendCompletion.Task;
});

using var httpClient = new HttpClient(handler.Object);
var httpClientFactory = new Mock<IHttpClientFactory>();
httpClientFactory.Setup(factory => factory.CreateClient("WayfarerApi")).Returns(httpClient);
var settings = new Mock<ISettingsService>();
settings.Setup(value => value.IsConfigured).Returns(true);
settings.Setup(value => value.ServerUrl).Returns("https://api.example.com");
var service = new GroupsService(
settings.Object,
Mock.Of<ILogger<GroupsService>>(),
httpClientFactory.Object);
using var cancellationSource = new CancellationTokenSource();

var resultTask = service.UpdatePeerVisibilityAsync(Guid.NewGuid(), disabled: true, cancellationSource.Token);
await sendStarted.Task;
cancellationSource.Cancel();

capturedCancellationToken.IsCancellationRequested.Should().BeTrue();
sendCompletion.SetCanceled(capturedCancellationToken);
(await resultTask).Should().BeFalse();
}
}
1 change: 1 addition & 0 deletions tests/WayfarerMobile.Tests/WayfarerMobile.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<Compile Include="..\..\src\WayfarerMobile\Data\Repositories\SegmentRepository.cs" Link="Production\SegmentRepository.cs" />
<Compile Include="..\..\src\WayfarerMobile\Interfaces\ITripContentService.cs" Link="Production\ITripContentService.cs" />
<Compile Include="..\..\src\WayfarerMobile\Interfaces\ITripMetadataBuilder.cs" Link="Production\ITripMetadataBuilder.cs" />
<Compile Include="..\..\src\WayfarerMobile\Services\GroupsService.cs" Link="Production\GroupsService.cs" />
<Compile Include="..\..\src\WayfarerMobile\Services\TripContentService.cs" Link="Production\TripContentService.cs" />
<!-- Test Framework -->
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.11" />
Expand Down
Loading