tests: finish adding tests for webhook

This commit is contained in:
Stevan Freeborn
2025-06-03 12:44:02 -05:00
parent 68ba283856
commit e616bdedda
2 changed files with 97 additions and 3 deletions
@@ -10,7 +10,8 @@ internal static class VerifySubscriptionHandler
[FromQuery(Name = "hub.lease_seconds")] string? leaseSeconds, [FromQuery(Name = "hub.lease_seconds")] string? leaseSeconds,
[FromServices] IOptions<SubscriptionOptions> subOptions, [FromServices] IOptions<SubscriptionOptions> subOptions,
[FromServices] ILogger<Program> logger, [FromServices] ILogger<Program> logger,
[FromServices] ConcurrentQueue<SubscribeTask> subscriptionQueue [FromServices] ConcurrentQueue<SubscribeTask> subscriptionQueue,
[FromServices] TimeProvider timeProvider
) )
{ {
if (mode is "denied") if (mode is "denied")
@@ -44,7 +45,7 @@ internal static class VerifySubscriptionHandler
{ {
CallbackUrl = subOptions.Value.CallbackUrl, CallbackUrl = subOptions.Value.CallbackUrl,
TopicUrl = topic, TopicUrl = topic,
ExpiresAt = DateTime.UtcNow.AddSeconds(parsedSeconds), ExpiresAt = timeProvider.GetUtcNow().AddSeconds(parsedSeconds),
}; };
subscriptionQueue.Enqueue(task); subscriptionQueue.Enqueue(task);
@@ -1,3 +1,5 @@
using System.Globalization;
namespace StevesBot.Webhook.Tests.Unit; namespace StevesBot.Webhook.Tests.Unit;
public class VerifySubscriptionHandlerTests public class VerifySubscriptionHandlerTests
@@ -5,6 +7,7 @@ public class VerifySubscriptionHandlerTests
private readonly Mock<IOptions<SubscriptionOptions>> _mockSubOptions = new(); private readonly Mock<IOptions<SubscriptionOptions>> _mockSubOptions = new();
private readonly Mock<ILogger<Program>> _mockLogger = new(); private readonly Mock<ILogger<Program>> _mockLogger = new();
private readonly ConcurrentQueue<SubscribeTask> _subscriptionQueue = new(); private readonly ConcurrentQueue<SubscribeTask> _subscriptionQueue = new();
private readonly Mock<TimeProvider> _mockTimeProvider = new();
[Fact] [Fact]
public void Handle_WhenModeIsDenied_ItShouldReturnBadRequest() public void Handle_WhenModeIsDenied_ItShouldReturnBadRequest()
@@ -14,6 +17,95 @@ public class VerifySubscriptionHandlerTests
result.Should().BeOfType<BadRequest<string>>(); result.Should().BeOfType<BadRequest<string>>();
} }
[Fact]
public void Handle_WhenTopicDoesNotMatch_ItShouldReturnNotFound()
{
SetupSubscriptionOptions(new() { TopicUrl = "expected-topic" });
var result = Handle("subscribe", "wrong-topic");
result.Should().BeOfType<NotFound>();
}
[Fact]
public void Handle_WhenModeIsSubscribeAndLeaseSecondsIsNotPresent_ItShouldReturnBadRequest()
{
var topic = "topic";
SetupSubscriptionOptions(new() { TopicUrl = topic });
var result = Handle("subscribe", topic, leaseSeconds: null);
result.Should().BeOfType<BadRequest<string>>();
}
[Fact]
public void Handle_WhenModeIsSubscribeAndLeaseSecondsIsInvalid_ItShouldReturnBadRequest()
{
var topic = "topic";
SetupSubscriptionOptions(new() { TopicUrl = topic });
var result = Handle("subscribe", topic, leaseSeconds: "invalid");
result.Should().BeOfType<BadRequest<string>>();
}
[Fact]
public void Handle_WhenModeIsUnsubscribe_ItShouldReturnOk()
{
var topic = "topic";
SetupSubscriptionOptions(new() { TopicUrl = topic });
var result = Handle("unsubscribe", topic, challenge: "challenge");
result.Should().BeOfType<ContentHttpResult>();
}
[Fact]
public void Handle_WhenModeIsSubscribe_ItShouldEnqueueSubscriptionTask()
{
var challenge = "challenge";
var topic = "topic";
var leaseSeconds = 3600;
var callbackUrl = "https://example.com/callback";
var now = DateTime.UtcNow;
_mockTimeProvider
.Setup(static tp => tp.GetUtcNow())
.Returns(now);
SetupSubscriptionOptions(new() { TopicUrl = topic, CallbackUrl = callbackUrl });
var result = Handle(
"subscribe",
topic,
challenge: challenge,
leaseSeconds: leaseSeconds.ToString(CultureInfo.InvariantCulture)
);
result.Should().BeOfType<ContentHttpResult>();
result.As<ContentHttpResult>().ResponseContent.Should().Be(challenge);
_subscriptionQueue.Count.Should().Be(1);
var task = _subscriptionQueue.TryDequeue(out var dequeuedTask);
task.Should().BeTrue();
dequeuedTask.Should().NotBeNull();
dequeuedTask!.CallbackUrl.Should().Be(callbackUrl);
dequeuedTask.TopicUrl.Should().Be(topic);
dequeuedTask.ExpiresAt.Should().Be(now.AddSeconds(leaseSeconds));
}
private void SetupSubscriptionOptions(SubscriptionOptions options)
{
_mockSubOptions
.Setup(static o => o.Value)
.Returns(options);
}
private IResult Handle(string mode, string topic, string? reason = null, string? challenge = null, string? leaseSeconds = null) private IResult Handle(string mode, string topic, string? reason = null, string? challenge = null, string? leaseSeconds = null)
{ {
return VerifySubscriptionHandler.Handle( return VerifySubscriptionHandler.Handle(
@@ -24,7 +116,8 @@ public class VerifySubscriptionHandlerTests
leaseSeconds, leaseSeconds,
_mockSubOptions.Object, _mockSubOptions.Object,
_mockLogger.Object, _mockLogger.Object,
_subscriptionQueue _subscriptionQueue,
_mockTimeProvider.Object
); );
} }
} }