Skip to content

Commit 6876adc

Browse files
Merge pull request #702 from PathfinderHonorManager/develop
Added background processing for grade change detection and achievement creation
2 parents 96c95ae + 8b6f81f commit 6876adc

File tree

15 files changed

+1398
-7
lines changed

15 files changed

+1398
-7
lines changed

.github/actions/setup-dotnet/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ runs:
66
- name: Set up .NET Core
77
uses: actions/setup-dotnet@v4.2.0
88
with:
9-
dotnet-version: '9.0.x'
9+
dotnet-version: '10.0.x'

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"type": "coreclr",
77
"request": "launch",
88
"preLaunchTask": "build",
9-
"program": "${workspaceFolder}/PathfinderHonorManager/bin/Debug/net9.0/PathfinderHonorManager.dll",
9+
"program": "${workspaceFolder}/PathfinderHonorManager/bin/Debug/net10.0/PathfinderHonorManager.dll",
1010
"args": [],
1111
"cwd": "${workspaceFolder}/PathfinderHonorManager",
1212
"stopAtEntry": false,

PathfinderHonorManager.Tests/Service/AchievementSyncBackgroundServiceTests.cs

Lines changed: 417 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
using System;
2+
using System.Linq;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using Microsoft.Extensions.Logging.Abstractions;
6+
using NUnit.Framework;
7+
using PathfinderHonorManager.Model;
8+
using PathfinderHonorManager.Service;
9+
10+
namespace PathfinderHonorManager.Tests.Service
11+
{
12+
[TestFixture]
13+
public class InMemoryGradeChangeQueueTests
14+
{
15+
private InMemoryGradeChangeQueue _queue;
16+
17+
[SetUp]
18+
public void SetUp()
19+
{
20+
_queue = new InMemoryGradeChangeQueue(NullLogger<InMemoryGradeChangeQueue>.Instance);
21+
}
22+
23+
[Test]
24+
public async Task TryEnqueueAsync_WithValidEvent_ReturnsTrue()
25+
{
26+
var gradeChange = new GradeChangeEvent(Guid.NewGuid(), 5, 6);
27+
28+
var result = await _queue.TryEnqueueAsync(gradeChange);
29+
30+
Assert.That(result, Is.True);
31+
}
32+
33+
[Test]
34+
public async Task TryEnqueueAsync_WithDuplicatePathfinderId_ReturnsFalse()
35+
{
36+
var pathfinderId = Guid.NewGuid();
37+
var gradeChange1 = new GradeChangeEvent(pathfinderId, 5, 6);
38+
var gradeChange2 = new GradeChangeEvent(pathfinderId, 6, 7);
39+
40+
await _queue.TryEnqueueAsync(gradeChange1);
41+
var result = await _queue.TryEnqueueAsync(gradeChange2);
42+
43+
Assert.That(result, Is.False);
44+
}
45+
46+
[Test]
47+
public void TryEnqueueAsync_WithNullEvent_ThrowsArgumentNullException()
48+
{
49+
Assert.ThrowsAsync<ArgumentNullException>(async () =>
50+
await _queue.TryEnqueueAsync(null));
51+
}
52+
53+
[Test]
54+
public async Task DequeueAllAsync_ReturnsEnqueuedItems()
55+
{
56+
var gradeChange1 = new GradeChangeEvent(Guid.NewGuid(), 5, 6);
57+
var gradeChange2 = new GradeChangeEvent(Guid.NewGuid(), 6, 7);
58+
await _queue.TryEnqueueAsync(gradeChange1);
59+
await _queue.TryEnqueueAsync(gradeChange2);
60+
61+
var items = await _queue.DequeueAllAsync(10);
62+
63+
Assert.That(items.Count(), Is.EqualTo(2));
64+
}
65+
66+
[Test]
67+
public async Task DequeueAllAsync_ReturnsItemsInFIFOOrder()
68+
{
69+
var pathfinderId1 = Guid.NewGuid();
70+
var pathfinderId2 = Guid.NewGuid();
71+
var pathfinderId3 = Guid.NewGuid();
72+
73+
var gradeChange1 = new GradeChangeEvent(pathfinderId1, 5, 6);
74+
var gradeChange2 = new GradeChangeEvent(pathfinderId2, 6, 7);
75+
var gradeChange3 = new GradeChangeEvent(pathfinderId3, 7, 8);
76+
77+
await _queue.TryEnqueueAsync(gradeChange1);
78+
await _queue.TryEnqueueAsync(gradeChange2);
79+
await _queue.TryEnqueueAsync(gradeChange3);
80+
81+
var items = (await _queue.DequeueAllAsync(10)).ToList();
82+
83+
Assert.That(items[0].PathfinderId, Is.EqualTo(pathfinderId1));
84+
Assert.That(items[1].PathfinderId, Is.EqualTo(pathfinderId2));
85+
Assert.That(items[2].PathfinderId, Is.EqualTo(pathfinderId3));
86+
}
87+
88+
[Test]
89+
public async Task DequeueAllAsync_RespectsMaxItems()
90+
{
91+
var gradeChange1 = new GradeChangeEvent(Guid.NewGuid(), 5, 6);
92+
var gradeChange2 = new GradeChangeEvent(Guid.NewGuid(), 6, 7);
93+
var gradeChange3 = new GradeChangeEvent(Guid.NewGuid(), 7, 8);
94+
95+
await _queue.TryEnqueueAsync(gradeChange1);
96+
await _queue.TryEnqueueAsync(gradeChange2);
97+
await _queue.TryEnqueueAsync(gradeChange3);
98+
99+
var items = await _queue.DequeueAllAsync(2);
100+
101+
Assert.That(items.Count(), Is.EqualTo(2));
102+
}
103+
104+
[Test]
105+
public async Task DequeueAllAsync_EmptyQueue_ReturnsEmptyCollection()
106+
{
107+
var items = await _queue.DequeueAllAsync(10);
108+
109+
Assert.That(items, Is.Empty);
110+
}
111+
112+
[Test]
113+
public async Task GetCountAsync_ReturnsCorrectCount()
114+
{
115+
var gradeChange1 = new GradeChangeEvent(Guid.NewGuid(), 5, 6);
116+
var gradeChange2 = new GradeChangeEvent(Guid.NewGuid(), 6, 7);
117+
118+
await _queue.TryEnqueueAsync(gradeChange1);
119+
await _queue.TryEnqueueAsync(gradeChange2);
120+
121+
var count = await _queue.GetCountAsync();
122+
123+
Assert.That(count, Is.EqualTo(2));
124+
}
125+
126+
[Test]
127+
public async Task GetCountAsync_EmptyQueue_ReturnsZero()
128+
{
129+
var count = await _queue.GetCountAsync();
130+
131+
Assert.That(count, Is.EqualTo(0));
132+
}
133+
134+
[Test]
135+
public async Task DequeueAllAsync_RemovesItemsFromQueue()
136+
{
137+
var gradeChange = new GradeChangeEvent(Guid.NewGuid(), 5, 6);
138+
await _queue.TryEnqueueAsync(gradeChange);
139+
140+
await _queue.DequeueAllAsync(10);
141+
var count = await _queue.GetCountAsync();
142+
143+
Assert.That(count, Is.EqualTo(0));
144+
}
145+
146+
[Test]
147+
public async Task DequeueAllAsync_AllowsReEnqueueOfSamePathfinderId()
148+
{
149+
var pathfinderId = Guid.NewGuid();
150+
var gradeChange1 = new GradeChangeEvent(pathfinderId, 5, 6);
151+
152+
await _queue.TryEnqueueAsync(gradeChange1);
153+
await _queue.DequeueAllAsync(10);
154+
155+
var gradeChange2 = new GradeChangeEvent(pathfinderId, 6, 7);
156+
var result = await _queue.TryEnqueueAsync(gradeChange2);
157+
158+
Assert.That(result, Is.True);
159+
}
160+
161+
[Test]
162+
public async Task ThreadSafety_MultipleConcurrentEnqueues_AllSucceed()
163+
{
164+
var tasks = Enumerable.Range(0, 10)
165+
.Select(i => Task.Run(async () =>
166+
{
167+
var gradeChange = new GradeChangeEvent(Guid.NewGuid(), 5, 6);
168+
return await _queue.TryEnqueueAsync(gradeChange);
169+
}))
170+
.ToArray();
171+
172+
var results = await Task.WhenAll(tasks);
173+
var count = await _queue.GetCountAsync();
174+
175+
Assert.That(results.All(r => r), Is.True);
176+
Assert.That(count, Is.EqualTo(10));
177+
}
178+
179+
[Test]
180+
public async Task ThreadSafety_ConcurrentEnqueueAndDequeue_WorksCorrectly()
181+
{
182+
var enqueueTask = Task.Run(async () =>
183+
{
184+
for (int i = 0; i < 20; i++)
185+
{
186+
var gradeChange = new GradeChangeEvent(Guid.NewGuid(), 5, 6);
187+
await _queue.TryEnqueueAsync(gradeChange);
188+
await Task.Delay(10);
189+
}
190+
});
191+
192+
var dequeueTask = Task.Run(async () =>
193+
{
194+
for (int i = 0; i < 10; i++)
195+
{
196+
await Task.Delay(30);
197+
await _queue.DequeueAllAsync(2);
198+
}
199+
});
200+
201+
await Task.WhenAll(enqueueTask, dequeueTask);
202+
var finalCount = await _queue.GetCountAsync();
203+
204+
Assert.That(finalCount, Is.GreaterThanOrEqualTo(0));
205+
}
206+
}
207+
}
208+

0 commit comments

Comments
 (0)