#8 use string type for ID to make implementation more agnostic to different ID types
This commit is contained in:
parent
a540221b7f
commit
18a5a64d4e
|
@ -63,7 +63,7 @@ namespace AccessQueuePlayground.Services
|
||||||
{
|
{
|
||||||
if (user.Active)
|
if (user.Active)
|
||||||
{
|
{
|
||||||
user.LatestResponse = await _accessService.RequestAccess(user.Id);
|
user.LatestResponse = await _accessService.RequestAccess(user.Id.ToString());
|
||||||
if (user.LatestResponse?.HasAccess ?? false)
|
if (user.LatestResponse?.HasAccess ?? false)
|
||||||
{
|
{
|
||||||
newStatus.AccessUsers.Add(user);
|
newStatus.AccessUsers.Add(user);
|
||||||
|
@ -95,7 +95,7 @@ namespace AccessQueuePlayground.Services
|
||||||
var user = _users[userId];
|
var user = _users[userId];
|
||||||
user.Active = false;
|
user.Active = false;
|
||||||
user.LatestResponse = null;
|
user.LatestResponse = null;
|
||||||
_accessService.RevokeAccess(userId);
|
_accessService.RevokeAccess(userId.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RevokeAllAccess()
|
public void RevokeAllAccess()
|
||||||
|
|
|
@ -17,14 +17,14 @@ namespace AccessQueueService.Controllers
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{id}")]
|
[Route("{id}")]
|
||||||
public async Task<AccessResponse> Get(Guid id)
|
public async Task<AccessResponse> Get(string id)
|
||||||
{
|
{
|
||||||
return await _accessService.RequestAccess(id);
|
return await _accessService.RequestAccess(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpDelete]
|
[HttpDelete]
|
||||||
[Route("{id}")]
|
[Route("{id}")]
|
||||||
public async Task<bool> Delete(Guid id)
|
public async Task<bool> Delete(string id)
|
||||||
{
|
{
|
||||||
return await _accessService.RevokeAccess(id);
|
return await _accessService.RevokeAccess(id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,12 @@ namespace AccessQueueService.Data
|
||||||
public int GetUnexpiredTicketsCount();
|
public int GetUnexpiredTicketsCount();
|
||||||
public int GetActiveTicketsCount(DateTime activeCutoff);
|
public int GetActiveTicketsCount(DateTime activeCutoff);
|
||||||
public int GetQueueCount();
|
public int GetQueueCount();
|
||||||
public AccessTicket? GetTicket(Guid userId);
|
public AccessTicket? GetTicket(string userId);
|
||||||
public void UpsertTicket(AccessTicket ticket);
|
public void UpsertTicket(AccessTicket ticket);
|
||||||
public int GetRequestsAhead(Guid userId);
|
public int GetRequestsAhead(string userId);
|
||||||
public void Enqueue(AccessTicket ticket);
|
public void Enqueue(AccessTicket ticket);
|
||||||
public int DeleteExpiredTickets();
|
public int DeleteExpiredTickets();
|
||||||
public bool RemoveUser(Guid userId);
|
public bool RemoveUser(string userId);
|
||||||
public bool DidDequeueUntilFull(int activeSeconds, int expirationSeconds, int capacityLimit);
|
public bool DidDequeueUntilFull(int activeSeconds, int expirationSeconds, int capacityLimit);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ namespace AccessQueueService.Data
|
||||||
{
|
{
|
||||||
public class TakeANumberAccessQueueRepo : IAccessQueueRepo
|
public class TakeANumberAccessQueueRepo : IAccessQueueRepo
|
||||||
{
|
{
|
||||||
private readonly Dictionary<Guid, AccessTicket> _accessTickets = [];
|
private readonly Dictionary<string, AccessTicket> _accessTickets = [];
|
||||||
private readonly Dictionary<Guid, ulong> _queueNumbers = [];
|
private readonly Dictionary<string, ulong> _queueNumbers = [];
|
||||||
private readonly Dictionary<ulong, AccessTicket> _accessQueue = [];
|
private readonly Dictionary<ulong, AccessTicket> _accessQueue = [];
|
||||||
|
|
||||||
private ulong _nowServing = 0;
|
private ulong _nowServing = 0;
|
||||||
|
@ -16,7 +16,7 @@ namespace AccessQueueService.Data
|
||||||
public int GetActiveTicketsCount(DateTime activeCutoff) => _accessTickets
|
public int GetActiveTicketsCount(DateTime activeCutoff) => _accessTickets
|
||||||
.Count(t => t.Value.ExpiresOn > DateTime.UtcNow && t.Value.LastActive > activeCutoff);
|
.Count(t => t.Value.ExpiresOn > DateTime.UtcNow && t.Value.LastActive > activeCutoff);
|
||||||
public int GetQueueCount() => (int)(_nextUnusedTicket - _nowServing);
|
public int GetQueueCount() => (int)(_nextUnusedTicket - _nowServing);
|
||||||
public int GetRequestsAhead(Guid userId)
|
public int GetRequestsAhead(string userId)
|
||||||
{
|
{
|
||||||
if(_queueNumbers.TryGetValue(userId, out var queueNumber))
|
if(_queueNumbers.TryGetValue(userId, out var queueNumber))
|
||||||
{
|
{
|
||||||
|
@ -50,7 +50,7 @@ namespace AccessQueueService.Data
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveUser(Guid userId)
|
public void RemoveUser(string userId)
|
||||||
{
|
{
|
||||||
_accessTickets.Remove(userId);
|
_accessTickets.Remove(userId);
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ namespace AccessQueueService.Data
|
||||||
return filledSpots == openSpots;
|
return filledSpots == openSpots;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccessTicket? GetTicket(Guid userId)
|
public AccessTicket? GetTicket(string userId)
|
||||||
{
|
{
|
||||||
return _accessTickets.TryGetValue(userId, out var ticket) ? ticket : null;
|
return _accessTickets.TryGetValue(userId, out var ticket) ? ticket : null;
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ namespace AccessQueueService.Data
|
||||||
_accessTickets[ticket.UserId] = ticket;
|
_accessTickets[ticket.UserId] = ticket;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IAccessQueueRepo.RemoveUser(Guid userId)
|
bool IAccessQueueRepo.RemoveUser(string userId)
|
||||||
{
|
{
|
||||||
if(_queueNumbers.TryGetValue(userId, out var queueNumber))
|
if(_queueNumbers.TryGetValue(userId, out var queueNumber))
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{
|
{
|
||||||
public class AccessTicket
|
public class AccessTicket
|
||||||
{
|
{
|
||||||
public Guid UserId { get; set; }
|
public string UserId { get; set; }
|
||||||
public DateTime ExpiresOn { get; set; }
|
public DateTime ExpiresOn { get; set; }
|
||||||
public DateTime LastActive { get; set; }
|
public DateTime LastActive { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace AccessQueueService.Services
|
||||||
public int UnexpiredTicketsCount => _accessQueueRepo.GetUnexpiredTicketsCount();
|
public int UnexpiredTicketsCount => _accessQueueRepo.GetUnexpiredTicketsCount();
|
||||||
public int ActiveTicketsCount => _accessQueueRepo.GetActiveTicketsCount(DateTime.UtcNow.AddSeconds(-_configuration.GetValue<int>("AccessQueue:ActivitySeconds")));
|
public int ActiveTicketsCount => _accessQueueRepo.GetActiveTicketsCount(DateTime.UtcNow.AddSeconds(-_configuration.GetValue<int>("AccessQueue:ActivitySeconds")));
|
||||||
public int QueueCount => _accessQueueRepo.GetQueueCount();
|
public int QueueCount => _accessQueueRepo.GetQueueCount();
|
||||||
public async Task<AccessResponse> RequestAccess(Guid userId)
|
public async Task<AccessResponse> RequestAccess(string userId)
|
||||||
{
|
{
|
||||||
await _queueLock.WaitAsync();
|
await _queueLock.WaitAsync();
|
||||||
try
|
try
|
||||||
|
@ -93,7 +93,7 @@ namespace AccessQueueService.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> RevokeAccess(Guid userId)
|
public async Task<bool> RevokeAccess(string userId)
|
||||||
{
|
{
|
||||||
await _queueLock.WaitAsync();
|
await _queueLock.WaitAsync();
|
||||||
try
|
try
|
||||||
|
|
|
@ -4,8 +4,8 @@ namespace AccessQueueService.Services
|
||||||
{
|
{
|
||||||
public interface IAccessService
|
public interface IAccessService
|
||||||
{
|
{
|
||||||
public Task<AccessResponse> RequestAccess(Guid userId);
|
public Task<AccessResponse> RequestAccess(string userId);
|
||||||
public Task<bool> RevokeAccess(Guid userId);
|
public Task<bool> RevokeAccess(string userId);
|
||||||
public int DeleteExpiredTickets();
|
public int DeleteExpiredTickets();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ namespace AccessQueueServiceTests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task RequestAccess_ShouldGrantAccess_WhenCapacityIsAvailable()
|
public async Task RequestAccess_ShouldGrantAccess_WhenCapacityIsAvailable()
|
||||||
{
|
{
|
||||||
var userId = Guid.NewGuid();
|
var userId = "user";
|
||||||
|
|
||||||
var response = await _accessService.RequestAccess(userId);
|
var response = await _accessService.RequestAccess(userId);
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ namespace AccessQueueServiceTests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task RequestAccess_ShouldReturnAccessResponse_WhenUserAlreadyHasTicket()
|
public async Task RequestAccess_ShouldReturnAccessResponse_WhenUserAlreadyHasTicket()
|
||||||
{
|
{
|
||||||
var userId = Guid.NewGuid();
|
var userId = "user";
|
||||||
await _accessService.RequestAccess(userId);
|
await _accessService.RequestAccess(userId);
|
||||||
|
|
||||||
var response = await _accessService.RequestAccess(userId);
|
var response = await _accessService.RequestAccess(userId);
|
||||||
|
@ -74,9 +74,9 @@ namespace AccessQueueServiceTests
|
||||||
{
|
{
|
||||||
for (int i = 0; i < CAP_LIMIT * 2; i++) // Fill double capacity
|
for (int i = 0; i < CAP_LIMIT * 2; i++) // Fill double capacity
|
||||||
{
|
{
|
||||||
await _accessService.RequestAccess(Guid.NewGuid());
|
await _accessService.RequestAccess(Guid.NewGuid().ToString());
|
||||||
}
|
}
|
||||||
var userId = Guid.NewGuid();
|
var userId = "user";
|
||||||
|
|
||||||
var response = await _accessService.RequestAccess(userId);
|
var response = await _accessService.RequestAccess(userId);
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ namespace AccessQueueServiceTests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task RevokeAccess_ShouldReturnTrue_WhenUserHasAccess()
|
public async Task RevokeAccess_ShouldReturnTrue_WhenUserHasAccess()
|
||||||
{
|
{
|
||||||
var userId = Guid.NewGuid();
|
var userId = "user";
|
||||||
await _accessService.RequestAccess(userId);
|
await _accessService.RequestAccess(userId);
|
||||||
|
|
||||||
var result = await _accessService.RevokeAccess(userId);
|
var result = await _accessService.RevokeAccess(userId);
|
||||||
|
@ -103,7 +103,7 @@ namespace AccessQueueServiceTests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task RevokeAccess_ShouldReturnFalse_WhenUserDoesNotHaveAccess()
|
public async Task RevokeAccess_ShouldReturnFalse_WhenUserDoesNotHaveAccess()
|
||||||
{
|
{
|
||||||
var userId = Guid.NewGuid();
|
var userId = "user";
|
||||||
|
|
||||||
var result = await _accessService.RevokeAccess(userId);
|
var result = await _accessService.RevokeAccess(userId);
|
||||||
|
|
||||||
|
@ -113,12 +113,12 @@ namespace AccessQueueServiceTests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task RequestAccess_ShouldQueueUser_AfterAccessRevoked()
|
public async Task RequestAccess_ShouldQueueUser_AfterAccessRevoked()
|
||||||
{
|
{
|
||||||
var userId = Guid.NewGuid();
|
var userId = "user";
|
||||||
await _accessService.RequestAccess(userId);
|
await _accessService.RequestAccess(userId);
|
||||||
|
|
||||||
for (int i = 0; i < CAP_LIMIT; i++) // Fill remaining slots
|
for (int i = 0; i < CAP_LIMIT; i++) // Fill remaining slots
|
||||||
{
|
{
|
||||||
await _accessService.RequestAccess(Guid.NewGuid());
|
await _accessService.RequestAccess(Guid.NewGuid().ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = await _accessService.RequestAccess(userId); // Request access before revoking
|
var response = await _accessService.RequestAccess(userId); // Request access before revoking
|
||||||
|
@ -136,9 +136,9 @@ namespace AccessQueueServiceTests
|
||||||
{
|
{
|
||||||
for (int i = 0; i < CAP_LIMIT; i++) // Fill slots without awaiting
|
for (int i = 0; i < CAP_LIMIT; i++) // Fill slots without awaiting
|
||||||
{
|
{
|
||||||
_ = _accessService.RequestAccess(Guid.NewGuid());
|
_ = _accessService.RequestAccess(Guid.NewGuid().ToString());
|
||||||
}
|
}
|
||||||
var response = await _accessService.RequestAccess(Guid.NewGuid()); // Request access before revoking
|
var response = await _accessService.RequestAccess(Guid.NewGuid().ToString()); // Request access before revoking
|
||||||
Assert.NotNull(response);
|
Assert.NotNull(response);
|
||||||
Assert.False(response.HasAccess);
|
Assert.False(response.HasAccess);
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ namespace AccessQueueServiceTests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task RequestAccess_ShouldUpdateExpirationTime_WhenRollingExpirationTrue()
|
public async Task RequestAccess_ShouldUpdateExpirationTime_WhenRollingExpirationTrue()
|
||||||
{
|
{
|
||||||
var userId = Guid.NewGuid();
|
var userId = "user";
|
||||||
var initialResponse = await _accessService.RequestAccess(userId);
|
var initialResponse = await _accessService.RequestAccess(userId);
|
||||||
await Task.Delay(ACT_MILLIS);
|
await Task.Delay(ACT_MILLIS);
|
||||||
var updatedResponse = await _accessService.RequestAccess(userId);
|
var updatedResponse = await _accessService.RequestAccess(userId);
|
||||||
|
@ -158,9 +158,9 @@ namespace AccessQueueServiceTests
|
||||||
{
|
{
|
||||||
for (int i = 0; i < CAP_LIMIT; i++)
|
for (int i = 0; i < CAP_LIMIT; i++)
|
||||||
{
|
{
|
||||||
await _accessService.RequestAccess(Guid.NewGuid());
|
await _accessService.RequestAccess(Guid.NewGuid().ToString());
|
||||||
}
|
}
|
||||||
var userId = Guid.NewGuid();
|
var userId = "user";
|
||||||
var response = await _accessService.RequestAccess(userId);
|
var response = await _accessService.RequestAccess(userId);
|
||||||
Assert.False(response.HasAccess);
|
Assert.False(response.HasAccess);
|
||||||
await Task.Delay(ACT_MILLIS);
|
await Task.Delay(ACT_MILLIS);
|
||||||
|
@ -171,13 +171,13 @@ namespace AccessQueueServiceTests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task RequestAccess_ShouldRevokeAccess_WhenExpired()
|
public async Task RequestAccess_ShouldRevokeAccess_WhenExpired()
|
||||||
{
|
{
|
||||||
var userId = Guid.NewGuid();
|
var userId = "user";
|
||||||
var response = await _accessService.RequestAccess(userId);
|
var response = await _accessService.RequestAccess(userId);
|
||||||
Assert.True(response.HasAccess);
|
Assert.True(response.HasAccess);
|
||||||
await Task.Delay(EXP_MILLIS);
|
await Task.Delay(EXP_MILLIS);
|
||||||
for (int i = 0; i < CAP_LIMIT; i++)
|
for (int i = 0; i < CAP_LIMIT; i++)
|
||||||
{
|
{
|
||||||
await _accessService.RequestAccess(Guid.NewGuid());
|
await _accessService.RequestAccess(Guid.NewGuid().ToString());
|
||||||
}
|
}
|
||||||
response = await _accessService.RequestAccess(userId);
|
response = await _accessService.RequestAccess(userId);
|
||||||
Assert.False(response.HasAccess);
|
Assert.False(response.HasAccess);
|
||||||
|
@ -186,13 +186,13 @@ namespace AccessQueueServiceTests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task RequestAccess_ShouldRetailAccess_WhenNotExpired()
|
public async Task RequestAccess_ShouldRetailAccess_WhenNotExpired()
|
||||||
{
|
{
|
||||||
var userId = Guid.NewGuid();
|
var userId = "user";
|
||||||
var response = await _accessService.RequestAccess(userId);
|
var response = await _accessService.RequestAccess(userId);
|
||||||
Assert.True(response.HasAccess);
|
Assert.True(response.HasAccess);
|
||||||
await Task.Delay(ACT_MILLIS);
|
await Task.Delay(ACT_MILLIS);
|
||||||
for (int i = 0; i < CAP_LIMIT; i++)
|
for (int i = 0; i < CAP_LIMIT; i++)
|
||||||
{
|
{
|
||||||
response = await _accessService.RequestAccess(Guid.NewGuid());
|
response = await _accessService.RequestAccess(Guid.NewGuid().ToString());
|
||||||
Assert.True(response.HasAccess);
|
Assert.True(response.HasAccess);
|
||||||
}
|
}
|
||||||
response = await _accessService.RequestAccess(userId);
|
response = await _accessService.RequestAccess(userId);
|
||||||
|
@ -202,11 +202,11 @@ namespace AccessQueueServiceTests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task RequestAccess_ShouldProcessBulkRequests()
|
public async Task RequestAccess_ShouldProcessBulkRequests()
|
||||||
{
|
{
|
||||||
var userId = Guid.NewGuid();
|
var userId = "user";
|
||||||
await _accessService.RequestAccess(userId);
|
await _accessService.RequestAccess(userId);
|
||||||
for (int i = 0; i < BULK_COUNT; i++)
|
for (int i = 0; i < BULK_COUNT; i++)
|
||||||
{
|
{
|
||||||
_ = _accessService.RequestAccess(Guid.NewGuid());
|
_ = _accessService.RequestAccess(Guid.NewGuid().ToString());
|
||||||
}
|
}
|
||||||
var response = await _accessService.RequestAccess(userId);
|
var response = await _accessService.RequestAccess(userId);
|
||||||
Assert.NotNull(response);
|
Assert.NotNull(response);
|
||||||
|
@ -220,15 +220,14 @@ namespace AccessQueueServiceTests
|
||||||
for (int i = 0; i < CAP_LIMIT; i++)
|
for (int i = 0; i < CAP_LIMIT; i++)
|
||||||
{
|
{
|
||||||
var elapsed = DateTime.UtcNow - start;
|
var elapsed = DateTime.UtcNow - start;
|
||||||
Console.WriteLine($"Elapsed time: {elapsed.TotalSeconds} s: Adding {i}");
|
await _accessService.RequestAccess(Guid.NewGuid().ToString());
|
||||||
await _accessService.RequestAccess(Guid.NewGuid());
|
|
||||||
await Task.Delay(ACT_MILLIS / CAP_LIMIT);
|
await Task.Delay(ACT_MILLIS / CAP_LIMIT);
|
||||||
}
|
}
|
||||||
var users = new[]
|
var users = new[]
|
||||||
{
|
{
|
||||||
Guid.NewGuid(),
|
"user1",
|
||||||
Guid.NewGuid(),
|
"user2",
|
||||||
Guid.NewGuid()
|
"user3"
|
||||||
};
|
};
|
||||||
|
|
||||||
await _accessService.RequestAccess(users[0]);
|
await _accessService.RequestAccess(users[0]);
|
||||||
|
@ -250,12 +249,12 @@ namespace AccessQueueServiceTests
|
||||||
{
|
{
|
||||||
for (int i = 0; i < CAP_LIMIT; i++)
|
for (int i = 0; i < CAP_LIMIT; i++)
|
||||||
{
|
{
|
||||||
await _accessService.RequestAccess(Guid.NewGuid());
|
await _accessService.RequestAccess(Guid.NewGuid().ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
var id1 = Guid.NewGuid();
|
var id1 = "user1";
|
||||||
var id2 = Guid.NewGuid();
|
var id2 = "user2";
|
||||||
var id3 = Guid.NewGuid();
|
var id3 = "user3";
|
||||||
|
|
||||||
var response1 = await _accessService.RequestAccess(id1);
|
var response1 = await _accessService.RequestAccess(id1);
|
||||||
var response2 = await _accessService.RequestAccess(id2);
|
var response2 = await _accessService.RequestAccess(id2);
|
||||||
|
|
Loading…
Reference in New Issue