Skip to content
Closed
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
49 changes: 49 additions & 0 deletions Services/Donut/DonutFlipSubscriptionService.Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Coflnet.Payments.Client.Api;
using Coflnet.Sky.Commands;
using Coflnet.Sky.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using NUnit.Framework;

namespace Coflnet.Sky.ModCommands.Services.Donut;

public class DonutFlipSubscriptionServiceTests
{
[Test]
public async Task ClosingOldConnectionKeepsReplacementSubscription()
{
var userApi = new Mock<IUserApi>();
userApi.Setup(u => u.UserUserIdOwnsProductSlugUntilGetAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(DateTime.UtcNow.AddDays(1));
var service = new DonutFlipSubscriptionService(userApi.Object, new ConfigurationBuilder().Build(), NullLogger<DonutFlipSubscriptionService>.Instance);
var oldConnection = CreateConnection();
var replacement = CreateConnection();

await service.RefreshSubscriptionAsync(oldConnection.Object);
await service.RefreshSubscriptionAsync(replacement.Object);
// the old socket closes after the replacement with the same id registered
service.RemoveConnection(oldConnection.Object);
await service.DeliverAsync(new LowPricedAuction
{
Auction = new SaveAuction(),
AdditionalProps = new Dictionary<string, string> { { "server", DonutServerContext.Name } }
});

replacement.Verify(c => c.SendFlip(It.IsAny<LowPricedAuction>()), Times.Once);
}

private static Mock<IFlipConnection> CreateConnection()
{
var connection = new Mock<IFlipConnection>();
connection.SetupGet(c => c.Id).Returns(42);
connection.SetupGet(c => c.UserId).Returns("1");
connection.SetupGet(c => c.GameServer).Returns(DonutServerContext.Name);
connection.Setup(c => c.SendFlip(It.IsAny<LowPricedAuction>())).ReturnsAsync(true);
return connection;
}
}
7 changes: 4 additions & 3 deletions Services/Donut/DonutFlipSubscriptionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public async Task RefreshSubscriptionAsync(IFlipConnection connection)

public void RemoveConnection(IFlipConnection connection)
{
subscribers.TryRemove(connection.Id, out _);
// A replacement connection reuses the same id, only remove the subscription this connection owns
subscribers.TryRemove(new(connection.Id, connection));
}

public async Task DeliverAsync(LowPricedAuction flip)
Expand All @@ -74,12 +75,12 @@ public async Task DeliverAsync(LowPricedAuction flip)
try
{
if (!await entry.Value.SendFlip(flip).ConfigureAwait(false))
subscribers.TryRemove(entry.Key, out _);
subscribers.TryRemove(entry);
}
catch (Exception e)
{
logger.LogError(e, "Failed to send Donut flip to connection {ConnectionId}", entry.Key);
subscribers.TryRemove(entry.Key, out _);
subscribers.TryRemove(entry);
}
}
}
Expand Down
Loading