AccessQueueService/AccessQueueServiceTests/AccessQueueRepoTests.cs

286 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using AccessQueueService.Data;
using AccessQueueService.Models;
using AccessQueueService.Services;
using Microsoft.Extensions.Configuration;
namespace AccessQueueServiceTests
{
public class AccessQueueRepoTests
{
private readonly TakeANumberAccessQueueRepo _repo;
public AccessQueueRepoTests()
{
_repo = new TakeANumberAccessQueueRepo();
}
[Fact]
public void GetUnexpiredTicketsCount_ReturnsCorrectCount()
{
_repo.UpsertTicket(new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow });
_repo.UpsertTicket(new AccessTicket { UserId = "b", ExpiresOn = DateTime.UtcNow.AddMinutes(-1), LastActive = DateTime.UtcNow });
Assert.Equal(1, _repo.GetUnexpiredTicketsCount());
}
[Fact]
public void GetActiveTicketsCount_ReturnsCorrectCount()
{
var activeCutoff = DateTime.UtcNow.AddMinutes(-5);
_repo.UpsertTicket(new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow });
_repo.UpsertTicket(new AccessTicket { UserId = "b", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow.AddMinutes(-10) });
Assert.Equal(1, _repo.GetActiveTicketsCount(activeCutoff));
}
[Fact]
public void GetQueueCount_ReturnsCorrectCount()
{
Assert.Equal(0, _repo.GetQueueCount());
_repo.Enqueue(new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow });
Assert.Equal(1, _repo.GetQueueCount());
}
[Fact]
public void GetRequestsAhead_ReturnsMinusOneIfUserNotInQueue()
{
Assert.Equal(-1, _repo.GetRequestsAhead("notfound"));
}
[Fact]
public void GetRequestsAhead_ReturnsCorrectNumber()
{
var ticket = new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow };
_repo.Enqueue(ticket);
Assert.Equal(0, _repo.GetRequestsAhead("a"));
}
[Fact]
public void Enqueue_AddsTicketToQueue()
{
var ticket = new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow };
_repo.Enqueue(ticket);
Assert.Equal(1, _repo.GetQueueCount());
Assert.Equal(0, _repo.GetRequestsAhead("a"));
}
[Fact]
public void DeleteExpiredTickets_RemovesExpiredTickets()
{
_repo.UpsertTicket(new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow.AddMinutes(-1), LastActive = DateTime.UtcNow });
_repo.UpsertTicket(new AccessTicket { UserId = "b", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow });
int removed = _repo.DeleteExpiredTickets();
Assert.Equal(1, removed);
Assert.NotNull(_repo.GetTicket("b"));
Assert.Null(_repo.GetTicket("a"));
}
[Fact]
public void DidDequeueUntilFull_FillsOpenSpots()
{
var ticket = new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
_repo.Enqueue(ticket);
bool result = _repo.DidDequeueUntilFull(60, 60, 1);
Assert.True(result);
Assert.NotNull(_repo.GetTicket("a"));
}
[Fact]
public void DidDequeueUntilFull_ReturnsTrueIfNoOpenSpots()
{
_repo.UpsertTicket(new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow });
bool result = _repo.DidDequeueUntilFull(60, 60, 0);
Assert.True(result);
}
[Fact]
public void GetTicket_ReturnsTicketIfExists()
{
var ticket = new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow };
_repo.UpsertTicket(ticket);
var found = _repo.GetTicket("a");
Assert.NotNull(found);
Assert.Equal("a", found.UserId);
}
[Fact]
public void GetTicket_ReturnsNullIfNotExists()
{
Assert.Null(_repo.GetTicket("notfound"));
}
[Fact]
public void UpsertTicket_AddsOrUpdatesTicket()
{
var ticket = new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow };
_repo.UpsertTicket(ticket);
Assert.NotNull(_repo.GetTicket("a"));
var updated = new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
_repo.UpsertTicket(updated);
Assert.Equal(updated.ExpiresOn, _repo.GetTicket("a")!.ExpiresOn);
}
[Fact]
public void RemoveUser_RemovesFromAllCollections()
{
var ticket = new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow };
_repo.Enqueue(ticket);
_repo.UpsertTicket(ticket);
bool removed = _repo.RemoveUser("a");
Assert.True(removed);
Assert.Null(_repo.GetTicket("a"));
Assert.Equal(-1, _repo.GetRequestsAhead("a"));
}
[Fact]
public void DidDequeueUntilFull_SkipsInactiveUser()
{
var inactive = new AccessTicket { UserId = "inactive", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow.AddMinutes(-10) };
var active = new AccessTicket { UserId = "active", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
_repo.Enqueue(inactive);
_repo.Enqueue(active);
bool result = _repo.DidDequeueUntilFull(5 * 60, 60, 1);
Assert.True(result);
Assert.Null(_repo.GetTicket("inactive"));
Assert.NotNull(_repo.GetTicket("active"));
}
[Fact]
public void Enqueue_QueuesUsersInOrder()
{
var ticket1 = new AccessTicket { UserId = "first", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow };
var ticket2 = new AccessTicket { UserId = "second", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow };
var ticket3 = new AccessTicket { UserId = "third", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow };
_repo.Enqueue(ticket1);
_repo.Enqueue(ticket2);
_repo.Enqueue(ticket3);
Assert.Equal(0, _repo.GetRequestsAhead("first"));
Assert.Equal(1, _repo.GetRequestsAhead("second"));
Assert.Equal(2, _repo.GetRequestsAhead("third"));
}
[Fact]
public void DidDequeueUntilFull_DequeuesUsersInOrder()
{
var ticket1 = new AccessTicket { UserId = "first", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
var ticket2 = new AccessTicket { UserId = "second", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
var ticket3 = new AccessTicket { UserId = "third", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
_repo.Enqueue(ticket1);
_repo.Enqueue(ticket2);
_repo.Enqueue(ticket3);
bool result = _repo.DidDequeueUntilFull(60 * 60, 60, 1);
Assert.True(result);
Assert.NotNull(_repo.GetTicket("first"));
Assert.Null(_repo.GetTicket("second"));
Assert.Null(_repo.GetTicket("third"));
}
[Fact]
public void Optimize_MaintainsQueueOrder()
{
var ticket1 = new AccessTicket { UserId = "first", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
var ticket2 = new AccessTicket { UserId = "second", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
var ticket3 = new AccessTicket { UserId = "third", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
_repo.Enqueue(ticket1);
_repo.Enqueue(ticket2);
_repo.Enqueue(ticket3);
_repo.DidDequeueUntilFull(60 * 60, 60, 1);
_repo.Optimize();
Assert.NotNull(_repo.GetTicket("first"));
Assert.Equal(0, _repo.GetRequestsAhead("second"));
Assert.Equal(1, _repo.GetRequestsAhead("third"));
Assert.Equal(0ul, _repo._nowServing);
_repo.DidDequeueUntilFull(60 * 60, 60, 2);
Assert.NotNull(_repo.GetTicket("second"));
Assert.Equal(0, _repo.GetRequestsAhead("third"));
}
[Fact]
public void Enqueue_MaintainsQueueOrder_WhenMaxValueExceeded()
{
var ticket1 = new AccessTicket { UserId = "first", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
var ticket2 = new AccessTicket { UserId = "second", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
var ticket3 = new AccessTicket { UserId = "third", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
_repo._nowServing = long.MaxValue - 1;
_repo._nextUnusedTicket = long.MaxValue - 1;
_repo.Enqueue(ticket1);
_repo.Enqueue(ticket2);
_repo.Enqueue(ticket3);
Assert.Equal(0ul, _repo._nowServing);
Assert.Equal(3ul, _repo._nextUnusedTicket);
Assert.Equal(0, _repo.GetRequestsAhead("first"));
Assert.Equal(2, _repo.GetRequestsAhead("third"));
}
[Fact]
public void ToState_ReturnsAccurateJson()
{
var ticketWithAccess = new AccessTicket { UserId = "access", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
var ticketWithoutAccess = new AccessTicket { UserId = "noAccess", LastActive = DateTime.UtcNow };
_repo.UpsertTicket(ticketWithAccess);
_repo.Enqueue(ticketWithoutAccess);
string stateJson = _repo.ToState();
var state = JsonSerializer.Deserialize<TakeANumberAccessQueueRepoState>(stateJson);
Assert.NotNull(state?.AccessQueue);
Assert.NotNull(state?.AccessTickets);
Assert.Single(state!.AccessTickets);
Assert.Single(state!.AccessQueue);
Assert.Equal(ticketWithAccess.UserId, state.AccessTickets.First().Key);
Assert.Equal(ticketWithAccess.ExpiresOn, state.AccessTickets.First().Value.ExpiresOn);
Assert.Equal(ticketWithAccess.LastActive, state.AccessTickets.First().Value.LastActive);
Assert.Equal(ticketWithoutAccess.UserId, state.AccessQueue.First().Value.UserId);
Assert.Equal(ticketWithoutAccess.LastActive, state.AccessQueue.First().Value.LastActive);
}
[Fact]
public void FromState_DeserializesJsonCorrectly()
{
var ticketWithAccess = new AccessTicket { UserId = "access", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
var ticketWithoutAccess = new AccessTicket { UserId = "noAccess", LastActive = DateTime.UtcNow };
_repo.UpsertTicket(ticketWithAccess);
_repo.Enqueue(ticketWithoutAccess);
string stateJson = _repo.ToState();
var deserializedRepo = TakeANumberAccessQueueRepo.FromState(stateJson);
Assert.Equal(1, deserializedRepo.GetUnexpiredTicketsCount());
Assert.Equal(1, deserializedRepo.GetQueueCount());
Assert.Equal(deserializedRepo.GetTicket("access")!.ExpiresOn, ticketWithAccess.ExpiresOn);
Assert.Null(deserializedRepo.GetTicket("noAccess"));
Assert.Equal(0, deserializedRepo.GetRequestsAhead("noAccess"));
}
}
}