feat(youtube): multiple stream notifications
Refactors the notification storage to support multiple stream IDs using a ConcurrentDictionary. This ensures that the bot can track and ignore duplicate notifications for multiple streams within a rolling 24-hour window, rather than only tracking the single most recent stream. - Updated ILastPostedStreamStore to include RemoveValuesOlderThan24Hours. - Switched LastPostedStreamStore to use ConcurrentDictionary with UTC timestamps. - Injected TimeProvider to enable deterministic testing of time-based expiration. - Added automatic cache pruning in NotificationHandler on every request. - Renamed Unit/LastPostedStreamStore.cs to Unit/LastPostedStreamStoreTests.cs and expanded test coverage.
This commit is contained in:
@@ -1,36 +0,0 @@
|
||||
namespace StevesBot.Webhook.Tests.Unit;
|
||||
|
||||
public class LastPostedStreamStoreTests
|
||||
{
|
||||
[Fact]
|
||||
public void SetValue_WhenCalledWithNull_ItShouldThrowArgumentNullException()
|
||||
{
|
||||
var store = new LastPostedStreamStore();
|
||||
|
||||
var act = () => store.SetValue(null!);
|
||||
|
||||
act.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasValue_WhenCalledWithNull_ItShouldThrowArgumentNullException()
|
||||
{
|
||||
var store = new LastPostedStreamStore();
|
||||
|
||||
var act = () => store.HasValue(null!);
|
||||
|
||||
act.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void SetValueHasValue_WhenCalled_ItShouldStoreValue()
|
||||
{
|
||||
var store = new LastPostedStreamStore();
|
||||
var streamId = "test-stream-id";
|
||||
|
||||
store.SetValue(streamId);
|
||||
|
||||
store.HasValue(streamId).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
namespace StevesBot.Webhook.Tests.Unit;
|
||||
|
||||
public class LastPostedStreamStoreTests
|
||||
{
|
||||
private readonly Mock<TimeProvider> _mockTimeProvider = new();
|
||||
private readonly LastPostedStreamStore _sut;
|
||||
|
||||
public LastPostedStreamStoreTests()
|
||||
{
|
||||
_sut = new(_mockTimeProvider.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetValue_WhenCalledWithNull_ItShouldThrowArgumentNullException()
|
||||
{
|
||||
var act = () => _sut.SetValue(null!);
|
||||
|
||||
act.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasValue_WhenCalledWithNull_ItShouldThrowArgumentNullException()
|
||||
{
|
||||
var act = () => _sut.HasValue(null!);
|
||||
|
||||
act.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void SetValueHasValue_WhenCalled_ItShouldStoreValue()
|
||||
{
|
||||
var streamId = "test-stream-id";
|
||||
|
||||
_sut.SetValue(streamId);
|
||||
|
||||
_sut.HasValue(streamId).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveValuesOlderThan24Hours_WhenCalled_ItShouldRemoveItemsOlderThan24Hours()
|
||||
{
|
||||
var oldStreamId = "test-stream-id-old";
|
||||
var currentStreamId = "test-stream-id-current";
|
||||
|
||||
var currentTime = DateTimeOffset.UtcNow;
|
||||
var invalidTime = DateTimeOffset.UtcNow.AddHours(-25);
|
||||
var validTime = DateTimeOffset.UtcNow.AddHours(-10);
|
||||
|
||||
_mockTimeProvider.SetupSequence(static m => m.GetUtcNow())
|
||||
.Returns(invalidTime)
|
||||
.Returns(validTime)
|
||||
.Returns(currentTime);
|
||||
|
||||
_sut.SetValue(oldStreamId);
|
||||
_sut.SetValue(currentStreamId);
|
||||
|
||||
_sut.RemoveValuesOlderThan24Hours();
|
||||
|
||||
_sut.HasValue(oldStreamId).Should().BeFalse();
|
||||
_sut.HasValue(currentStreamId).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user