summaryrefslogtreecommitdiff
path: root/packages/backend/test/unit/queue/processors
diff options
context:
space:
mode:
authorおさむのひと <46447427+samunohito@users.noreply.github.com>2024-10-11 20:59:36 +0900
committerGitHub <noreply@github.com>2024-10-11 20:59:36 +0900
commita2cd6a7709ffacfabb738deac22cb0fd1eb7d493 (patch)
treedb473d5f5c9339db9798073c54409b3acb0cb848 /packages/backend/test/unit/queue/processors
parentfix: admin/emoji/update で不正なエラーが発生する (#14750) (diff)
downloadsharkey-a2cd6a7709ffacfabb738deac22cb0fd1eb7d493.tar.gz
sharkey-a2cd6a7709ffacfabb738deac22cb0fd1eb7d493.tar.bz2
sharkey-a2cd6a7709ffacfabb738deac22cb0fd1eb7d493.zip
feat(backend): 7日間運営のアクティビティがないサーバを自動的に招待制にする (#14746)
* feat(backend): 7日間運営のアクティビティがないサーバを自動的に招待制にする * fix RoleService. * fix * fix * fix * add test and fix * fix * fix CHANGELOG.md * fix test
Diffstat (limited to 'packages/backend/test/unit/queue/processors')
-rw-r--r--packages/backend/test/unit/queue/processors/CheckModeratorsActivityProcessorService.ts235
1 files changed, 235 insertions, 0 deletions
diff --git a/packages/backend/test/unit/queue/processors/CheckModeratorsActivityProcessorService.ts b/packages/backend/test/unit/queue/processors/CheckModeratorsActivityProcessorService.ts
new file mode 100644
index 0000000000..b783320aa0
--- /dev/null
+++ b/packages/backend/test/unit/queue/processors/CheckModeratorsActivityProcessorService.ts
@@ -0,0 +1,235 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { jest } from '@jest/globals';
+import { Test, TestingModule } from '@nestjs/testing';
+import * as lolex from '@sinonjs/fake-timers';
+import { addHours, addSeconds, subDays, subHours, subSeconds } from 'date-fns';
+import { CheckModeratorsActivityProcessorService } from '@/queue/processors/CheckModeratorsActivityProcessorService.js';
+import { MiUser, UserProfilesRepository, UsersRepository } from '@/models/_.js';
+import { IdService } from '@/core/IdService.js';
+import { RoleService } from '@/core/RoleService.js';
+import { GlobalModule } from '@/GlobalModule.js';
+import { MetaService } from '@/core/MetaService.js';
+import { DI } from '@/di-symbols.js';
+import { QueueLoggerService } from '@/queue/QueueLoggerService.js';
+
+const baseDate = new Date(Date.UTC(2000, 11, 15, 12, 0, 0));
+
+describe('CheckModeratorsActivityProcessorService', () => {
+ let app: TestingModule;
+ let clock: lolex.InstalledClock;
+ let service: CheckModeratorsActivityProcessorService;
+
+ // --------------------------------------------------------------------------------------
+
+ let usersRepository: UsersRepository;
+ let userProfilesRepository: UserProfilesRepository;
+ let idService: IdService;
+ let roleService: jest.Mocked<RoleService>;
+
+ // --------------------------------------------------------------------------------------
+
+ async function createUser(data: Partial<MiUser> = {}) {
+ const id = idService.gen();
+ const user = await usersRepository
+ .insert({
+ id: id,
+ username: `user_${id}`,
+ usernameLower: `user_${id}`.toLowerCase(),
+ ...data,
+ })
+ .then(x => usersRepository.findOneByOrFail(x.identifiers[0]));
+
+ await userProfilesRepository.insert({
+ userId: user.id,
+ });
+
+ return user;
+ }
+
+ function mockModeratorRole(users: MiUser[]) {
+ roleService.getModerators.mockReset();
+ roleService.getModerators.mockResolvedValue(users);
+ }
+
+ // --------------------------------------------------------------------------------------
+
+ beforeAll(async () => {
+ app = await Test
+ .createTestingModule({
+ imports: [
+ GlobalModule,
+ ],
+ providers: [
+ CheckModeratorsActivityProcessorService,
+ IdService,
+ {
+ provide: RoleService, useFactory: () => ({ getModerators: jest.fn() }),
+ },
+ {
+ provide: MetaService, useFactory: () => ({ fetch: jest.fn() }),
+ },
+ {
+ provide: QueueLoggerService, useFactory: () => ({
+ logger: ({
+ createSubLogger: () => ({
+ info: jest.fn(),
+ warn: jest.fn(),
+ succ: jest.fn(),
+ }),
+ }),
+ }),
+ },
+ ],
+ })
+ .compile();
+
+ usersRepository = app.get(DI.usersRepository);
+ userProfilesRepository = app.get(DI.userProfilesRepository);
+
+ service = app.get(CheckModeratorsActivityProcessorService);
+ idService = app.get(IdService);
+ roleService = app.get(RoleService) as jest.Mocked<RoleService>;
+
+ app.enableShutdownHooks();
+ });
+
+ beforeEach(async () => {
+ clock = lolex.install({
+ now: new Date(baseDate),
+ shouldClearNativeTimers: true,
+ });
+ });
+
+ afterEach(async () => {
+ clock.uninstall();
+ await usersRepository.delete({});
+ await userProfilesRepository.delete({});
+ roleService.getModerators.mockReset();
+ });
+
+ afterAll(async () => {
+ await app.close();
+ });
+
+ // --------------------------------------------------------------------------------------
+
+ describe('evaluateModeratorsInactiveDays', () => {
+ test('[isModeratorsInactive] inactiveなモデレーターがいても他のモデレーターがアクティブなら"運営が非アクティブ"としてみなされない', async () => {
+ const [user1, user2, user3, user4] = await Promise.all([
+ // 期限よりも1秒新しいタイミングでアクティブ化(セーフ)
+ createUser({ lastActiveDate: subDays(addSeconds(baseDate, 1), 7) }),
+ // 期限ちょうどにアクティブ化(セーフ)
+ createUser({ lastActiveDate: subDays(baseDate, 7) }),
+ // 期限よりも1秒古いタイミングでアクティブ化(アウト)
+ createUser({ lastActiveDate: subDays(subSeconds(baseDate, 1), 7) }),
+ // 対象外
+ createUser({ lastActiveDate: null }),
+ ]);
+
+ mockModeratorRole([user1, user2, user3, user4]);
+
+ const result = await service.evaluateModeratorsInactiveDays();
+ expect(result.isModeratorsInactive).toBe(false);
+ expect(result.inactiveModerators).toEqual([user3]);
+ });
+
+ test('[isModeratorsInactive] 全員非アクティブなら"運営が非アクティブ"としてみなされる', async () => {
+ const [user1, user2] = await Promise.all([
+ // 期限よりも1秒古いタイミングでアクティブ化(アウト)
+ createUser({ lastActiveDate: subDays(subSeconds(baseDate, 1), 7) }),
+ // 対象外
+ createUser({ lastActiveDate: null }),
+ ]);
+
+ mockModeratorRole([user1, user2]);
+
+ const result = await service.evaluateModeratorsInactiveDays();
+ expect(result.isModeratorsInactive).toBe(true);
+ expect(result.inactiveModerators).toEqual([user1]);
+ });
+
+ test('[countdown] 猶予まで24時間ある場合、猶予1日として計算される', async () => {
+ const [user1, user2] = await Promise.all([
+ createUser({ lastActiveDate: subDays(baseDate, 8) }),
+ // 猶予はこのユーザ基準で計算される想定。
+ // 期限まで残り24時間->猶予1日として計算されるはずである
+ createUser({ lastActiveDate: subDays(baseDate, 6) }),
+ ]);
+
+ mockModeratorRole([user1, user2]);
+
+ const result = await service.evaluateModeratorsInactiveDays();
+ expect(result.isModeratorsInactive).toBe(false);
+ expect(result.inactiveModerators).toEqual([user1]);
+ expect(result.inactivityLimitCountdown).toBe(1);
+ });
+
+ test('[countdown] 猶予まで25時間ある場合、猶予1日として計算される', async () => {
+ const [user1, user2] = await Promise.all([
+ createUser({ lastActiveDate: subDays(baseDate, 8) }),
+ // 猶予はこのユーザ基準で計算される想定。
+ // 期限まで残り25時間->猶予1日として計算されるはずである
+ createUser({ lastActiveDate: subDays(addHours(baseDate, 1), 6) }),
+ ]);
+
+ mockModeratorRole([user1, user2]);
+
+ const result = await service.evaluateModeratorsInactiveDays();
+ expect(result.isModeratorsInactive).toBe(false);
+ expect(result.inactiveModerators).toEqual([user1]);
+ expect(result.inactivityLimitCountdown).toBe(1);
+ });
+
+ test('[countdown] 猶予まで23時間ある場合、猶予0日として計算される', async () => {
+ const [user1, user2] = await Promise.all([
+ createUser({ lastActiveDate: subDays(baseDate, 8) }),
+ // 猶予はこのユーザ基準で計算される想定。
+ // 期限まで残り23時間->猶予0日として計算されるはずである
+ createUser({ lastActiveDate: subDays(subHours(baseDate, 1), 6) }),
+ ]);
+
+ mockModeratorRole([user1, user2]);
+
+ const result = await service.evaluateModeratorsInactiveDays();
+ expect(result.isModeratorsInactive).toBe(false);
+ expect(result.inactiveModerators).toEqual([user1]);
+ expect(result.inactivityLimitCountdown).toBe(0);
+ });
+
+ test('[countdown] 期限ちょうどの場合、猶予0日として計算される', async () => {
+ const [user1, user2] = await Promise.all([
+ createUser({ lastActiveDate: subDays(baseDate, 8) }),
+ // 猶予はこのユーザ基準で計算される想定。
+ // 期限ちょうど->猶予0日として計算されるはずである
+ createUser({ lastActiveDate: subDays(baseDate, 7) }),
+ ]);
+
+ mockModeratorRole([user1, user2]);
+
+ const result = await service.evaluateModeratorsInactiveDays();
+ expect(result.isModeratorsInactive).toBe(false);
+ expect(result.inactiveModerators).toEqual([user1]);
+ expect(result.inactivityLimitCountdown).toBe(0);
+ });
+
+ test('[countdown] 期限より1時間超過している場合、猶予-1日として計算される', async () => {
+ const [user1, user2] = await Promise.all([
+ createUser({ lastActiveDate: subDays(baseDate, 8) }),
+ // 猶予はこのユーザ基準で計算される想定。
+ // 期限より1時間超過->猶予-1日として計算されるはずである
+ createUser({ lastActiveDate: subDays(subHours(baseDate, 1), 7) }),
+ ]);
+
+ mockModeratorRole([user1, user2]);
+
+ const result = await service.evaluateModeratorsInactiveDays();
+ expect(result.isModeratorsInactive).toBe(true);
+ expect(result.inactiveModerators).toEqual([user1, user2]);
+ expect(result.inactivityLimitCountdown).toBe(-1);
+ });
+ });
+});