계정 아이콘 등록과 목록 내리기 제한을 조정한다

This commit is contained in:
2026-09-24 15:46:11 +00:00
parent 4bf812b601
commit 8823434610
9 changed files with 138 additions and 153 deletions
+14 -49
View File
@@ -5,33 +5,15 @@ import { createInMemoryUserRepository } from '../src/auth/inMemoryUserRepository
const DAY_MS = 24 * 60 * 60 * 1000;
describe('user icon library', () => {
it('keeps five immutable active icons and enforces the rolling upload window', async () => {
it('allows uploads without a cooldown while keeping five immutable active icons', async () => {
const users = createInMemoryUserRepository();
const user = await users.createUser({ username: 'five-icons', password: 'password' });
const start = new Date('2026-08-01T00:00:00.000Z');
for (let index = 0; index < 5; index += 1) {
const now = new Date(start.getTime() + index * DAY_MS);
const stored = await users.addIconForWindow(
user.id,
`immutable-${index}.png`,
1,
now,
new Date(now.getTime() - DAY_MS),
5
);
const now = new Date(start.getTime() + index);
const stored = await users.addIconForWindow(user.id, `immutable-${index}.png`, 1, now, 5);
expect(stored.ok).toBe(true);
if (index === 0) {
const blocked = await users.addIconForWindow(
user.id,
'too-soon.png',
1,
new Date(now.getTime() + DAY_MS - 1),
new Date(now.getTime() - 1),
5
);
expect(blocked).toEqual({ ok: false, reason: 'COOLDOWN' });
}
}
const icons = await users.listIcons(user.id);
@@ -42,40 +24,19 @@ describe('user icon library', () => {
'immutable-3.png',
'immutable-4.png',
]);
const overLimit = await users.addIconForWindow(
user.id,
'sixth.png',
1,
new Date(start.getTime() + 5 * DAY_MS),
new Date(start.getTime() + 4 * DAY_MS),
5
);
const overLimit = await users.addIconForWindow(user.id, 'sixth.png', 1, new Date(start.getTime() + 5), 5);
expect(overLimit).toEqual({ ok: false, reason: 'LIMIT' });
});
it('retires without deleting the durable record and allows retirement only every seven days', async () => {
it('retires without deleting the durable record and allows one retirement per rolling 24 hours', async () => {
const users = createInMemoryUserRepository();
const user = await users.createUser({ username: 'retire-icons', password: 'password' });
const firstAt = new Date('2026-08-01T00:00:00.000Z');
const first = await users.addIconForWindow(
user.id,
'hall-of-fame.png',
1,
firstAt,
new Date(firstAt.getTime() - DAY_MS),
5
);
const first = await users.addIconForWindow(user.id, 'hall-of-fame.png', 1, firstAt, 5);
expect(first.ok).toBe(true);
if (!first.ok) return;
const secondAt = new Date(firstAt.getTime() + DAY_MS);
const second = await users.addIconForWindow(
user.id,
'next.png',
1,
secondAt,
new Date(secondAt.getTime() - DAY_MS),
5
);
const secondAt = new Date(firstAt.getTime() + 1);
const second = await users.addIconForWindow(user.id, 'next.png', 1, secondAt, 5);
expect(second.ok).toBe(true);
if (!second.ok) return;
@@ -83,7 +44,7 @@ describe('user icon library', () => {
user.id,
first.icon.id,
secondAt,
new Date(secondAt.getTime() - 7 * DAY_MS)
new Date(secondAt.getTime() - DAY_MS)
);
expect(retired.ok).toBe(true);
expect(await users.listIcons(user.id)).toHaveLength(1);
@@ -94,9 +55,13 @@ describe('user icon library', () => {
const blocked = await users.retireIconForWindow(
user.id,
second.icon.id,
new Date(secondAt.getTime() + 7 * DAY_MS - 1),
new Date(secondAt.getTime() + DAY_MS - 1),
new Date(secondAt.getTime() - 1)
);
expect(blocked).toEqual({ ok: false, reason: 'COOLDOWN' });
const allowedAt = new Date(secondAt.getTime() + DAY_MS);
await expect(
users.retireIconForWindow(user.id, second.icon.id, allowedAt, new Date(allowedAt.getTime() - DAY_MS))
).resolves.toMatchObject({ ok: true });
});
});