diff --git a/packages/backend/test/misc/noOpCaches.ts b/packages/backend/test/misc/noOpCaches.ts deleted file mode 100644 index 39a0d0ea62..0000000000 --- a/packages/backend/test/misc/noOpCaches.ts +++ /dev/null @@ -1,212 +0,0 @@ -/* - * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import * as Redis from 'ioredis'; -import { Inject } from '@nestjs/common'; -import { FakeInternalEventService } from './FakeInternalEventService.js'; -import type { BlockingsRepository, FollowingsRepository, MiUser, MutingsRepository, NoteThreadMutingsRepository, RenoteMutingsRepository, UserProfilesRepository, UsersRepository, ChannelFollowingsRepository, InstancesRepository } from '@/models/_.js'; -import type { MiLocalUser } from '@/models/User.js'; -import { MemoryKVCache, MemorySingleCache, RedisKVCache, RedisSingleCache } from '@/misc/cache.js'; -import { QuantumKVCache, QuantumKVOpts } from '@/misc/QuantumKVCache.js'; -import { CacheService, FollowStats } from '@/core/CacheService.js'; -import { DI } from '@/di-symbols.js'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { InternalEventService } from '@/core/InternalEventService.js'; -import { UtilityService } from '@/core/UtilityService.js'; -import { IdService } from '@/core/IdService.js'; - -export function noOpRedis() { - return { - set: () => Promise.resolve(), - get: () => Promise.resolve(null), - del: () => Promise.resolve(), - on: () => {}, - off: () => {}, - } as unknown as Redis.Redis; -} - -export class NoOpCacheService extends CacheService { - public readonly fakeRedis: { - [K in keyof Redis.Redis]: Redis.Redis[K]; - }; - public readonly fakeInternalEventService: FakeInternalEventService; - - constructor( - @Inject(DI.usersRepository) - usersRepository: UsersRepository, - - @Inject(DI.userProfilesRepository) - userProfilesRepository: UserProfilesRepository, - - @Inject(DI.mutingsRepository) - mutingsRepository: MutingsRepository, - - @Inject(DI.blockingsRepository) - blockingsRepository: BlockingsRepository, - - @Inject(DI.renoteMutingsRepository) - renoteMutingsRepository: RenoteMutingsRepository, - - @Inject(DI.followingsRepository) - followingsRepository: FollowingsRepository, - - @Inject(DI.noteThreadMutingsRepository) - noteThreadMutingsRepository: NoteThreadMutingsRepository, - - @Inject(DI.channelFollowingsRepository) - channelFollowingsRepository: ChannelFollowingsRepository, - - @Inject(DI.instancesRepository) - instancesRepository: InstancesRepository, - - @Inject(UserEntityService) - userEntityService: UserEntityService, - - @Inject(UtilityService) - utilityService: UtilityService, - - @Inject(IdService) - idService: IdService, - ) { - const fakeRedis = noOpRedis(); - const fakeInternalEventService = new FakeInternalEventService(); - - super( - fakeRedis, - fakeRedis, - usersRepository, - userProfilesRepository, - mutingsRepository, - blockingsRepository, - renoteMutingsRepository, - followingsRepository, - noteThreadMutingsRepository, - channelFollowingsRepository, - instancesRepository, - userEntityService, - fakeInternalEventService, - utilityService, - idService, - ); - - this.fakeRedis = fakeRedis; - this.fakeInternalEventService = fakeInternalEventService; - - // Override caches - this.userByIdCache = new NoOpMemoryKVCache(); - this.localUserByNativeTokenCache = new NoOpMemoryKVCache(); - this.localUserByIdCache = new NoOpMemoryKVCache(); - this.uriPersonCache = new NoOpMemoryKVCache(); - this.userProfileCache = NoOpQuantumKVCache.copy(this.userProfileCache, fakeInternalEventService); - this.userMutingsCache = NoOpQuantumKVCache.copy(this.userMutingsCache, fakeInternalEventService); - this.userBlockingCache = NoOpQuantumKVCache.copy(this.userBlockingCache, fakeInternalEventService); - this.userBlockedCache = NoOpQuantumKVCache.copy(this.userBlockedCache, fakeInternalEventService); - this.renoteMutingsCache = NoOpQuantumKVCache.copy(this.renoteMutingsCache, fakeInternalEventService); - this.threadMutingsCache = NoOpQuantumKVCache.copy(this.threadMutingsCache, fakeInternalEventService); - this.noteMutingsCache = NoOpQuantumKVCache.copy(this.noteMutingsCache, fakeInternalEventService); - this.userFollowingsCache = NoOpQuantumKVCache.copy(this.userFollowingsCache, fakeInternalEventService); - this.userFollowersCache = NoOpQuantumKVCache.copy(this.userFollowersCache, fakeInternalEventService); - this.hibernatedUserCache = NoOpQuantumKVCache.copy(this.hibernatedUserCache, fakeInternalEventService); - this.userFollowStatsCache = new NoOpMemoryKVCache(); - this.translationsCache = NoOpRedisKVCache.copy(this.translationsCache, fakeRedis); - this.userFollowingChannelsCache = NoOpQuantumKVCache.copy(this.userFollowingChannelsCache, fakeInternalEventService); - } -} - -export class NoOpMemoryKVCache extends MemoryKVCache { - constructor() { - super(-1); - } -} - -export class NoOpMemorySingleCache extends MemorySingleCache { - constructor() { - super(-1); - } -} - -export class NoOpRedisKVCache extends RedisKVCache { - constructor(opts?: { - redis?: Redis.Redis; - fetcher?: RedisKVCache['fetcher']; - toRedisConverter?: RedisKVCache['toRedisConverter']; - fromRedisConverter?: RedisKVCache['fromRedisConverter']; - }) { - super( - opts?.redis ?? noOpRedis(), - 'no-op', - { - lifetime: -1, - memoryCacheLifetime: -1, - fetcher: opts?.fetcher, - toRedisConverter: opts?.toRedisConverter, - fromRedisConverter: opts?.fromRedisConverter, - }, - ); - } - - public static copy(cache: RedisKVCache, redis?: Redis.Redis): NoOpRedisKVCache { - return new NoOpRedisKVCache({ - redis, - fetcher: cache.fetcher, - toRedisConverter: cache.toRedisConverter, - fromRedisConverter: cache.fromRedisConverter, - }); - } -} - -export class NoOpRedisSingleCache extends RedisSingleCache { - constructor(opts?: { - redis?: Redis.Redis; - fetcher?: RedisSingleCache['fetcher']; - toRedisConverter?: RedisSingleCache['toRedisConverter']; - fromRedisConverter?: RedisSingleCache['fromRedisConverter']; - }) { - super( - opts?.redis ?? noOpRedis(), - 'no-op', - { - lifetime: -1, - memoryCacheLifetime: -1, - fetcher: opts?.fetcher, - toRedisConverter: opts?.toRedisConverter, - fromRedisConverter: opts?.fromRedisConverter, - }, - ); - } - - public static copy(cache: RedisSingleCache, redis?: Redis.Redis): NoOpRedisSingleCache { - return new NoOpRedisSingleCache({ - redis, - fetcher: cache.fetcher, - toRedisConverter: cache.toRedisConverter, - fromRedisConverter: cache.fromRedisConverter, - }); - } -} - -export class NoOpQuantumKVCache extends QuantumKVCache { - constructor(opts: Omit, 'lifetime'> & { - internalEventService?: InternalEventService, - }) { - super( - opts.internalEventService ?? new FakeInternalEventService(), - 'no-op', - { - ...opts, - lifetime: -1, - }, - ); - } - - public static copy(cache: QuantumKVCache, internalEventService?: InternalEventService): NoOpQuantumKVCache { - return new NoOpQuantumKVCache({ - internalEventService, - fetcher: cache.fetcher, - bulkFetcher: cache.bulkFetcher, - onChanged: cache.onChanged, - }); - } -} diff --git a/packages/backend/test/unit/AnnouncementService.ts b/packages/backend/test/unit/AnnouncementService.ts index ab3b6961c0..826c856135 100644 --- a/packages/backend/test/unit/AnnouncementService.ts +++ b/packages/backend/test/unit/AnnouncementService.ts @@ -8,8 +8,9 @@ process.env.NODE_ENV = 'test'; import { jest } from '@jest/globals'; import { ModuleMocker } from 'jest-mock'; import { Test } from '@nestjs/testing'; -import { NoOpCacheService } from '../misc/noOpCaches.js'; -import { FakeInternalEventService } from '../misc/FakeInternalEventService.js'; +import { FakeCacheManagementService } from '../misc/FakeCacheManagementService.js'; +import { MockInternalEventService } from '../misc/MockInternalEventService.js'; +import { CacheManagementService } from '@/core/CacheManagementService.js'; import { GlobalModule } from '@/GlobalModule.js'; import { AnnouncementService } from '@/core/AnnouncementService.js'; import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js'; @@ -23,11 +24,11 @@ import type { } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { genAidx } from '@/misc/id/aidx.js'; -import { CacheService } from '@/core/CacheService.js'; import { IdService } from '@/core/IdService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; import { RoleService } from '@/core/RoleService.js'; +import { CoreModule } from '@/core/CoreModule.js'; import { secureRndstr } from '@/misc/secure-rndstr.js'; import type { TestingModule } from '@nestjs/testing'; import type { MockFunctionMetadata } from 'jest-mock'; @@ -42,7 +43,7 @@ describe('AnnouncementService', () => { let announcementReadsRepository: AnnouncementReadsRepository; let globalEventService: jest.Mocked; let moderationLogService: jest.Mocked; - let roleService: jest.Mocked; + let cacheManagementService: CacheManagementService; function createUser(data: Partial = {}) { const un = secureRndstr(16); @@ -66,20 +67,11 @@ describe('AnnouncementService', () => { .then(x => announcementsRepository.findOneByOrFail(x.identifiers[0])); } - beforeEach(async () => { + beforeAll(async () => { app = await Test.createTestingModule({ imports: [ GlobalModule, - ], - providers: [ - AnnouncementService, - AnnouncementEntityService, - CacheService, - IdService, - InternalEventService, - GlobalEventService, - ModerationLogService, - RoleService, + CoreModule, ], }) .useMocker((token) => { @@ -99,19 +91,27 @@ describe('AnnouncementService', () => { .overrideProvider(RoleService).useValue({ getUserRoles: jest.fn((_) => []), }) - .overrideProvider(InternalEventService).useClass(FakeInternalEventService) - .overrideProvider(CacheService).useClass(NoOpCacheService) + // TODO should we remove this now that cache is cleared? + .overrideProvider(InternalEventService).useClass(MockInternalEventService) + .overrideProvider(CacheManagementService).useClass(FakeCacheManagementService) .compile(); + await app.init(); app.enableShutdownHooks(); + }); + afterAll(async () => { + await app.close(); + }); + + beforeEach(() => { announcementService = app.get(AnnouncementService); usersRepository = app.get(DI.usersRepository); announcementsRepository = app.get(DI.announcementsRepository); announcementReadsRepository = app.get(DI.announcementReadsRepository); globalEventService = app.get(GlobalEventService) as jest.Mocked; moderationLogService = app.get(ModerationLogService) as jest.Mocked; - roleService = app.get(RoleService) as jest.Mocked; + cacheManagementService = app.get(CacheManagementService); }); afterEach(async () => { @@ -121,8 +121,10 @@ describe('AnnouncementService', () => { announcementsRepository.delete({}), announcementReadsRepository.delete({}), ]); - - await app.close(); + moderationLogService.log.mockReset(); + globalEventService.publishMainStream.mockReset(); + globalEventService.publishBroadcastStream.mockReset(); + cacheManagementService.clear(); }); describe('getUnreadAnnouncements', () => { diff --git a/packages/backend/test/unit/FetchInstanceMetadataService.ts b/packages/backend/test/unit/FetchInstanceMetadataService.ts index 812ee38703..13c26ba665 100644 --- a/packages/backend/test/unit/FetchInstanceMetadataService.ts +++ b/packages/backend/test/unit/FetchInstanceMetadataService.ts @@ -7,8 +7,10 @@ process.env.NODE_ENV = 'test'; import { jest } from '@jest/globals'; import { Test } from '@nestjs/testing'; -import { Redis } from 'ioredis'; +import { GodOfTimeService } from '../misc/GodOfTimeService.js'; +import { MockRedis } from '../misc/MockRedis.js'; import type { TestingModule } from '@nestjs/testing'; +import type { InstancesRepository } from '@/models/_.js'; import { GlobalModule } from '@/GlobalModule.js'; import { FetchInstanceMetadataService } from '@/core/FetchInstanceMetadataService.js'; import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; @@ -16,67 +18,69 @@ import { HttpRequestService } from '@/core/HttpRequestService.js'; import { LoggerService } from '@/core/LoggerService.js'; import { UtilityService } from '@/core/UtilityService.js'; import { IdService } from '@/core/IdService.js'; -import { EnvService } from '@/core/EnvService.js'; +import { CacheManagementService } from '@/core/CacheManagementService.js'; +import { CoreModule } from '@/core/CoreModule.js'; import { DI } from '@/di-symbols.js'; - -function mockRedis() { - const hash = {} as any; - const set = jest.fn((key: string, value) => { - const ret = hash[key]; - hash[key] = value; - return ret; - }); - return set; -} +import { TimeService } from '@/core/TimeService.js'; describe('FetchInstanceMetadataService', () => { let app: TestingModule; - let fetchInstanceMetadataService: jest.Mocked; + let fetchInstanceMetadataService: FetchInstanceMetadataService; let federatedInstanceService: jest.Mocked; let httpRequestService: jest.Mocked; - let redisClient: jest.Mocked; + let redisClient: MockRedis; + let instancesRepository: InstancesRepository; + let cacheManagementService: CacheManagementService; + let timeService: GodOfTimeService; - beforeEach(async () => { + beforeAll(async () => { app = await Test .createTestingModule({ imports: [ GlobalModule, - ], - providers: [ - FetchInstanceMetadataService, - LoggerService, - UtilityService, - IdService, - EnvService, + CoreModule, ], }) - .useMocker((token) => { - if (token === HttpRequestService) { - return { getJson: jest.fn(), getHtml: jest.fn(), send: jest.fn() }; - } else if (token === FederatedInstanceService) { - return { fetchOrRegister: jest.fn() }; - } else if (token === DI.redis) { - return mockRedis; - } - return null; - }) + .overrideProvider(TimeService).useClass(GodOfTimeService) + .overrideProvider(HttpRequestService).useValue({ getJson: jest.fn(), getHtml: jest.fn(), send: jest.fn() }) + .overrideProvider(FederatedInstanceService).useValue({ fetchOrRegister: jest.fn() }) + .overrideProvider(DI.redis).useClass(MockRedis) + .overrideProvider(DI.redisForSub).useClass(MockRedis) + .overrideProvider(DI.redisForPub).useClass(MockRedis) .compile(); + await app.init(); app.enableShutdownHooks(); - fetchInstanceMetadataService = app.get(FetchInstanceMetadataService) as jest.Mocked; + fetchInstanceMetadataService = app.get(FetchInstanceMetadataService); federatedInstanceService = app.get(FederatedInstanceService) as jest.Mocked; - redisClient = app.get(DI.redis) as jest.Mocked; httpRequestService = app.get(HttpRequestService) as jest.Mocked; + instancesRepository = app.get(DI.instancesRepository); + cacheManagementService = app.get(CacheManagementService); + timeService = app.get(TimeService); + redisClient = app.get(DI.redis); }); - afterEach(async () => { + afterAll(async () => { await app.close(); }); + beforeEach(() => { + federatedInstanceService.fetchOrRegister.mockReset(); + httpRequestService.getJson.mockReset(); + httpRequestService.getHtml.mockReset(); + httpRequestService.send.mockReset(); + redisClient.mockReset(); + timeService.resetToNow(); + }); + + afterEach(async () => { + await instancesRepository.delete({}); + cacheManagementService.clear(); + }); + test('Lock and update', async () => { - redisClient.set = mockRedis(); - const now = Date.now(); + const now = timeService.now; federatedInstanceService.fetchOrRegister.mockResolvedValue({ infoUpdatedAt: { getTime: () => { return now - 10 * 1000 * 60 * 60 * 24; } } } as any); httpRequestService.getJson.mockImplementation(() => { throw Error(); }); const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock'); @@ -90,8 +94,7 @@ describe('FetchInstanceMetadataService', () => { }); test('Lock and don\'t update', async () => { - redisClient.set = mockRedis(); - const now = Date.now(); + const now = timeService.now; federatedInstanceService.fetchOrRegister.mockResolvedValue({ infoUpdatedAt: { getTime: () => now } } as any); httpRequestService.getJson.mockImplementation(() => { throw Error(); }); const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock'); @@ -105,8 +108,7 @@ describe('FetchInstanceMetadataService', () => { }); test('Do nothing when lock not acquired', async () => { - redisClient.set = mockRedis(); - const now = Date.now(); + const now = timeService.now; federatedInstanceService.fetchOrRegister.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any); httpRequestService.getJson.mockImplementation(() => { throw Error(); }); await fetchInstanceMetadataService.tryLock('example.com'); @@ -121,8 +123,7 @@ describe('FetchInstanceMetadataService', () => { }); test('Do when lock not acquired but forced', async () => { - redisClient.set = mockRedis(); - const now = Date.now(); + const now = timeService.now; federatedInstanceService.fetchOrRegister.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any); httpRequestService.getJson.mockImplementation(() => { throw Error(); }); await fetchInstanceMetadataService.tryLock('example.com'); diff --git a/packages/backend/test/unit/RoleService.ts b/packages/backend/test/unit/RoleService.ts index edeac6f9ce..6e908c128c 100644 --- a/packages/backend/test/unit/RoleService.ts +++ b/packages/backend/test/unit/RoleService.ts @@ -5,17 +5,16 @@ process.env.NODE_ENV = 'test'; -import { setTimeout } from 'node:timers/promises'; import { jest } from '@jest/globals'; import { ModuleMocker } from 'jest-mock'; import { Test } from '@nestjs/testing'; -import * as lolex from '@sinonjs/fake-timers'; -import { NoOpCacheService } from '../misc/noOpCaches.js'; -import { FakeInternalEventService } from '../misc/FakeInternalEventService.js'; import type { TestingModule } from '@nestjs/testing'; import type { MockFunctionMetadata } from 'jest-mock'; +import { GodOfTimeService } from '../misc/GodOfTimeService.js'; +import { CacheManagementService } from '@/core/CacheManagementService.js'; import { GlobalModule } from '@/GlobalModule.js'; import { RoleService } from '@/core/RoleService.js'; +import { CoreModule } from '@/core/CoreModule.js'; import { InstancesRepository, MetasRepository, @@ -38,6 +37,7 @@ import { NotificationService } from '@/core/NotificationService.js'; import { RoleCondFormulaValue } from '@/models/Role.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { InternalEventService } from '@/core/InternalEventService.js'; +import { TimeService } from '@/core/TimeService.js'; const moduleMocker = new ModuleMocker(global); @@ -51,7 +51,8 @@ describe('RoleService', () => { let meta: jest.Mocked; let metasRepository: MetasRepository; let notificationService: jest.Mocked; - let clock: lolex.InstalledClock; + let cacheManagementService: CacheManagementService; + let timeService: GodOfTimeService; async function createUser(data: Partial = {}) { if (data.host != null) { @@ -59,8 +60,8 @@ describe('RoleService', () => { .createQueryBuilder('instance') .insert() .values({ - id: genAidx(Date.now()), - firstRetrievedAt: new Date(), + id: genAidx(timeService.now), + firstRetrievedAt: timeService.date, host: data.host, }) .orIgnore() @@ -69,7 +70,7 @@ describe('RoleService', () => { const un = secureRndstr(16); const x = await usersRepository.insert({ - id: genAidx(Date.now()), + id: genAidx(timeService.now), username: un, usernameLower: un, ...data, @@ -85,9 +86,9 @@ describe('RoleService', () => { async function createRole(data: Partial = {}) { const x = await rolesRepository.insert({ - id: genAidx(Date.now()), - updatedAt: new Date(), - lastUsedAt: new Date(), + id: genAidx(timeService.now), + updatedAt: timeService.date, + lastUsedAt: timeService.date, name: '', description: '', ...data, @@ -105,8 +106,8 @@ describe('RoleService', () => { } async function assignRole(args: Partial) { - const id = genAidx(Date.now()); - const expiresAt = new Date(); + const id = genAidx(timeService.now); + const expiresAt = timeService.date; expiresAt.setDate(expiresAt.getDate() + 1); await roleAssignmentsRepository.insert({ @@ -119,37 +120,14 @@ describe('RoleService', () => { } function aidx() { - return genAidx(Date.now()); + return genAidx(timeService.now); } - beforeEach(async () => { - clock = lolex.install({ - now: new Date(), - shouldClearNativeTimers: true, - }); - + beforeAll(async () => { app = await Test.createTestingModule({ imports: [ GlobalModule, - ], - providers: [ - RoleService, - CacheService, - IdService, - GlobalEventService, - UserEntityService, - { - provide: NotificationService, - useFactory: () => ({ - createNotification: jest.fn(), - }), - }, - { - provide: NotificationService.name, - useExisting: NotificationService, - }, - MetaService, - InternalEventService, + CoreModule, ], }) .useMocker((token) => { @@ -160,10 +138,11 @@ describe('RoleService', () => { } }) .overrideProvider(MetaService).useValue({ fetch: jest.fn() }) - .overrideProvider(InternalEventService).useClass(FakeInternalEventService) - .overrideProvider(CacheService).useClass(NoOpCacheService) + .overrideProvider(TimeService).useClass(GodOfTimeService) + .overrideProvider(NotificationService).useValue({ createNotification: jest.fn() }) .compile(); + await app.init(); app.enableShutdownHooks(); roleService = app.get(RoleService); @@ -172,16 +151,25 @@ describe('RoleService', () => { rolesRepository = app.get(DI.rolesRepository); roleAssignmentsRepository = app.get(DI.roleAssignmentsRepository); metasRepository = app.get(DI.metasRepository); + cacheManagementService = app.get(CacheManagementService); + + timeService = app.get(TimeService); + timeService.resetToNow(); meta = app.get(DI.meta) as jest.Mocked; notificationService = app.get(NotificationService) as jest.Mocked; + }); - await roleService.onModuleInit(); + afterAll(async () => { + await app.close(); + }); + + beforeEach(() => { + notificationService.createNotification.mockReset(); + timeService.resetToNow(); }); afterEach(async () => { - clock.uninstall(); - await Promise.all([ metasRepository.delete({}), usersRepository.delete({}), @@ -189,7 +177,7 @@ describe('RoleService', () => { roleAssignmentsRepository.delete({}), ]); - await app.close(); + cacheManagementService.clear(); }); describe('getUserPolicies', () => { @@ -282,25 +270,28 @@ describe('RoleService', () => { }, }, }); - await roleService.assign(user.id, role.id, new Date(Date.now() + (1000 * 60 * 60 * 24))); + await roleService.assign(user.id, role.id, new Date(timeService.now + (1000 * 60 * 60 * 24))); meta.policies = { canManageCustomEmojis: false, }; + // Condition 1: user has role immediately after assigning const result = await roleService.getUserPolicies(user.id); expect(result.canManageCustomEmojis).toBe(true); - clock.tick('25:00:00'); + timeService.now += 1000 * 60 * 60 * 25; // 25h + // Condition 2: user loses role within 1hr after expiration const resultAfter25h = await roleService.getUserPolicies(user.id); expect(resultAfter25h.canManageCustomEmojis).toBe(false); await roleService.assign(user.id, role.id); // ストリーミング経由で反映されるまでちょっと待つ - clock.uninstall(); - await setTimeout(100); + // Wait 100ms for the task queue to complete. + await new Promise(r => setTimeout(r, 100)); + // Condition 3: user regains role within 100ms after assigning again const resultAfter25hAgain = await roleService.getUserPolicies(user.id); expect(resultAfter25hAgain.canManageCustomEmojis).toBe(true); }); @@ -318,11 +309,11 @@ describe('RoleService', () => { await Promise.all([ assignRole({ userId: adminUser1.id, roleId: role1.id }), - assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(timeService.now - 1000) }), assignRole({ userId: modeUser1.id, roleId: role2.id }), - assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(timeService.now - 1000) }), assignRole({ userId: normalUser1.id, roleId: role3.id }), - assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(timeService.now - 1000) }), ]); const result = await roleService.getModeratorIds({ @@ -344,11 +335,11 @@ describe('RoleService', () => { await Promise.all([ assignRole({ userId: adminUser1.id, roleId: role1.id }), - assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(timeService.now - 1000) }), assignRole({ userId: modeUser1.id, roleId: role2.id }), - assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(timeService.now - 1000) }), assignRole({ userId: normalUser1.id, roleId: role3.id }), - assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(timeService.now - 1000) }), ]); const result = await roleService.getModeratorIds({ @@ -370,11 +361,11 @@ describe('RoleService', () => { await Promise.all([ assignRole({ userId: adminUser1.id, roleId: role1.id }), - assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(timeService.now - 1000) }), assignRole({ userId: modeUser1.id, roleId: role2.id }), - assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(timeService.now - 1000) }), assignRole({ userId: normalUser1.id, roleId: role3.id }), - assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(timeService.now - 1000) }), ]); const result = await roleService.getModeratorIds({ @@ -396,11 +387,11 @@ describe('RoleService', () => { await Promise.all([ assignRole({ userId: adminUser1.id, roleId: role1.id }), - assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(timeService.now - 1000) }), assignRole({ userId: modeUser1.id, roleId: role2.id }), - assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(timeService.now - 1000) }), assignRole({ userId: normalUser1.id, roleId: role3.id }), - assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(timeService.now - 1000) }), ]); const result = await roleService.getModeratorIds({ @@ -422,11 +413,11 @@ describe('RoleService', () => { await Promise.all([ assignRole({ userId: adminUser1.id, roleId: role1.id }), - assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(timeService.now - 1000) }), assignRole({ userId: modeUser1.id, roleId: role2.id }), - assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(timeService.now - 1000) }), assignRole({ userId: normalUser1.id, roleId: role3.id }), - assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(timeService.now - 1000) }), ]); const result = await roleService.getModeratorIds({ @@ -496,8 +487,8 @@ describe('RoleService', () => { await Promise.all([ assignRole({ userId: adminUser1.id, roleId: role1.id }), - assignRole({ userId: modeUser1.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }), - assignRole({ userId: rootUser.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: modeUser1.id, roleId: role2.id, expiresAt: new Date(timeService.now - 1000) }), + assignRole({ userId: rootUser.id, roleId: role2.id, expiresAt: new Date(timeService.now - 1000) }), assignRole({ userId: normalUser1.id, roleId: role3.id }), ]); @@ -745,7 +736,7 @@ describe('RoleService', () => { }); test('ユーザが作成されてから指定期間経過した', async () => { - const base = new Date(); + const base = timeService.date; base.setMinutes(base.getMinutes() - 5); const d1 = new Date(base); @@ -778,7 +769,7 @@ describe('RoleService', () => { }); test('ユーザが作成されてから指定期間経っていない', async () => { - const base = new Date(); + const base = timeService.date; base.setMinutes(base.getMinutes() - 5); const d1 = new Date(base); @@ -941,8 +932,7 @@ describe('RoleService', () => { await roleService.assign(user.id, role.id); - clock.uninstall(); - await setTimeout(100); + timeService.now += 100; const assignments = await roleAssignmentsRepository.find({ where: { @@ -969,8 +959,7 @@ describe('RoleService', () => { await roleService.assign(user.id, role.id); - clock.uninstall(); - await setTimeout(100); + timeService.now += 100; const assignments = await roleAssignmentsRepository.find({ where: { diff --git a/packages/backend/test/unit/SystemWebhookService.ts b/packages/backend/test/unit/SystemWebhookService.ts index 61187e9f2a..0204f1da3d 100644 --- a/packages/backend/test/unit/SystemWebhookService.ts +++ b/packages/backend/test/unit/SystemWebhookService.ts @@ -19,6 +19,8 @@ import { DI } from '@/di-symbols.js'; import { QueueService } from '@/core/QueueService.js'; import { LoggerService } from '@/core/LoggerService.js'; import { SystemWebhookService } from '@/core/SystemWebhookService.js'; +import { CacheManagementService } from '@/core/CacheManagementService.js'; +import { CoreModule } from '@/core/CoreModule.js'; describe('SystemWebhookService', () => { let app: TestingModule; @@ -29,6 +31,7 @@ describe('SystemWebhookService', () => { let usersRepository: UsersRepository; let systemWebhooksRepository: SystemWebhooksRepository; let idService: IdService; + let cacheManagementService: CacheManagementService; let queueService: jest.Mocked; // -------------------------------------------------------------------------------------- @@ -61,58 +64,48 @@ describe('SystemWebhookService', () => { // -------------------------------------------------------------------------------------- - async function beforeAllImpl() { + beforeAll(async () => { app = await Test .createTestingModule({ imports: [ GlobalModule, - ], - providers: [ - SystemWebhookService, - IdService, - LoggerService, - GlobalEventService, - { - provide: QueueService, useFactory: () => ({ systemWebhookDeliver: jest.fn() }), - }, - { - provide: ModerationLogService, useFactory: () => ({ log: () => Promise.resolve() }), - }, + CoreModule, ], }) + .overrideProvider(QueueService).useValue({ systemWebhookDeliver: jest.fn() }) + .overrideProvider(ModerationLogService).useValue({ log: () => Promise.resolve() }) .compile(); + await app.init(); + app.enableShutdownHooks(); + usersRepository = app.get(DI.usersRepository); systemWebhooksRepository = app.get(DI.systemWebhooksRepository); service = app.get(SystemWebhookService); idService = app.get(IdService); + cacheManagementService = app.get(CacheManagementService); queueService = app.get(QueueService) as jest.Mocked; + }); - app.enableShutdownHooks(); - } - - async function afterAllImpl() { + afterAll(async () => { await app.close(); - } + }); - async function beforeEachImpl() { + beforeEach(async () => { root = await createUser({ username: 'root', usernameLower: 'root' }); - } + }); - async function afterEachImpl() { + afterEach(async () => { await usersRepository.delete({}); await systemWebhooksRepository.delete({}); - } + queueService.systemWebhookDeliver.mockReset(); + cacheManagementService.clear(); + }); // -------------------------------------------------------------------------------------- describe('アプリを毎回作り直す必要のないグループ', () => { - beforeAll(beforeAllImpl); - afterAll(afterAllImpl); - beforeEach(beforeEachImpl); - afterEach(afterEachImpl); - describe('fetchSystemWebhooks', () => { test('フィルタなし', async () => { const webhook1 = await createWebhook({ @@ -298,16 +291,6 @@ describe('SystemWebhookService', () => { }); describe('アプリを毎回作り直す必要があるグループ', () => { - beforeEach(async () => { - await beforeAllImpl(); - await beforeEachImpl(); - }); - - afterEach(async () => { - await afterEachImpl(); - await afterAllImpl(); - }); - describe('enqueueSystemWebhook', () => { test('キューに追加成功', async () => { const webhook = await createWebhook({ diff --git a/packages/backend/test/unit/UserSearchService.ts b/packages/backend/test/unit/UserSearchService.ts index 8be47aea20..305e0ccc71 100644 --- a/packages/backend/test/unit/UserSearchService.ts +++ b/packages/backend/test/unit/UserSearchService.ts @@ -11,8 +11,10 @@ import { FollowingsRepository, InstancesRepository, MiUser, UserProfilesReposito import { IdService } from '@/core/IdService.js'; import { GlobalModule } from '@/GlobalModule.js'; import { DI } from '@/di-symbols.js'; +import { CacheManagementService } from '@/core/CacheManagementService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { genAidx } from '@/misc/id/aidx.js'; +import { CoreModule } from '@/core/CoreModule.js'; describe('UserSearchService', () => { let app: TestingModule; @@ -22,6 +24,7 @@ describe('UserSearchService', () => { let usersRepository: UsersRepository; let followingsRepository: FollowingsRepository; let idService: IdService; + let cacheManagementService: CacheManagementService; let userProfilesRepository: UserProfilesRepository; let root: MiUser; @@ -103,17 +106,12 @@ describe('UserSearchService', () => { .createTestingModule({ imports: [ GlobalModule, + CoreModule, ], - providers: [ - UserSearchService, - { - provide: UserEntityService, useFactory: jest.fn(() => ({ - // とりあえずIDが返れば確認が出来るので - packMany: (value: any) => value, - })), - }, - IdService, - ], + }) + .overrideProvider(UserEntityService).useValue({ + // とりあえずIDが返れば確認が出来るので + packMany: (value: any) => value, }) .compile(); @@ -127,6 +125,7 @@ describe('UserSearchService', () => { service = app.get(UserSearchService); idService = app.get(IdService); + cacheManagementService = app.get(CacheManagementService); }); beforeEach(async () => { @@ -145,6 +144,7 @@ describe('UserSearchService', () => { afterEach(async () => { await usersRepository.delete({}); + cacheManagementService.clear(); }); afterAll(async () => { diff --git a/packages/backend/test/unit/UserWebhookService.ts b/packages/backend/test/unit/UserWebhookService.ts index a2a85e9489..8a0d761095 100644 --- a/packages/backend/test/unit/UserWebhookService.ts +++ b/packages/backend/test/unit/UserWebhookService.ts @@ -15,6 +15,8 @@ import { DI } from '@/di-symbols.js'; import { QueueService } from '@/core/QueueService.js'; import { LoggerService } from '@/core/LoggerService.js'; import { UserWebhookService } from '@/core/UserWebhookService.js'; +import { CacheManagementService } from '@/core/CacheManagementService.js'; +import { CoreModule } from '@/core/CoreModule.js'; describe('UserWebhookService', () => { let app: TestingModule; @@ -25,6 +27,7 @@ describe('UserWebhookService', () => { let usersRepository: UsersRepository; let userWebhooksRepository: WebhooksRepository; let idService: IdService; + let cacheManagementService: CacheManagementService; let queueService: jest.Mocked; // -------------------------------------------------------------------------------------- @@ -58,55 +61,47 @@ describe('UserWebhookService', () => { // -------------------------------------------------------------------------------------- - async function beforeAllImpl() { + beforeAll(async () => { app = await Test .createTestingModule({ imports: [ GlobalModule, - ], - providers: [ - UserWebhookService, - IdService, - LoggerService, - GlobalEventService, - { - provide: QueueService, useFactory: () => ({ userWebhookDeliver: jest.fn() }), - }, + CoreModule, ], }) + .overrideProvider(QueueService).useValue({ userWebhookDeliver: jest.fn() }) .compile(); + await app.init(); + app.enableShutdownHooks(); + usersRepository = app.get(DI.usersRepository); userWebhooksRepository = app.get(DI.webhooksRepository); service = app.get(UserWebhookService); idService = app.get(IdService); + cacheManagementService = app.get(CacheManagementService); queueService = app.get(QueueService) as jest.Mocked; + }); - app.enableShutdownHooks(); - } - - async function afterAllImpl() { + afterAll(async () => { await app.close(); - } + }); - async function beforeEachImpl() { + beforeEach(async () => { root = await createUser({ username: 'root', usernameLower: 'root' }); - } + }); - async function afterEachImpl() { + afterEach(async () => { await usersRepository.delete({}); await userWebhooksRepository.delete({}); - } + queueService.userWebhookDeliver.mockReset(); + cacheManagementService.clear(); + }); // -------------------------------------------------------------------------------------- describe('アプリを毎回作り直す必要のないグループ', () => { - beforeAll(beforeAllImpl); - afterAll(afterAllImpl); - beforeEach(beforeEachImpl); - afterEach(afterEachImpl); - describe('fetchSystemWebhooks', () => { test('フィルタなし', async () => { const webhook1 = await createWebhook({ @@ -243,16 +238,6 @@ describe('UserWebhookService', () => { }); describe('アプリを毎回作り直す必要があるグループ', () => { - beforeEach(async () => { - await beforeAllImpl(); - await beforeEachImpl(); - }); - - afterEach(async () => { - await afterEachImpl(); - await afterAllImpl(); - }); - describe('enqueueUserWebhook', () => { test('キューに追加成功', async () => { const webhook = await createWebhook({ diff --git a/packages/backend/test/unit/WebhookTestService.ts b/packages/backend/test/unit/WebhookTestService.ts index 736aac40b4..db22c87fcb 100644 --- a/packages/backend/test/unit/WebhookTestService.ts +++ b/packages/backend/test/unit/WebhookTestService.ts @@ -15,6 +15,8 @@ import { IdService } from '@/core/IdService.js'; import { DI } from '@/di-symbols.js'; import { QueueService } from '@/core/QueueService.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js'; +import { CacheManagementService } from '@/core/CacheManagementService.js'; +import { CoreModule } from '@/core/CoreModule.js'; describe('WebhookTestService', () => { let app: TestingModule; @@ -28,6 +30,7 @@ describe('WebhookTestService', () => { let userWebhookService: jest.Mocked; let systemWebhookService: jest.Mocked; let idService: IdService; + let cacheManagementService: CacheManagementService; let root: MiUser; let alice: MiUser; @@ -53,44 +56,40 @@ describe('WebhookTestService', () => { app = await Test.createTestingModule({ imports: [ GlobalModule, + CoreModule, ], - providers: [ - WebhookTestService, - IdService, - { - provide: CustomEmojiService, useFactory: () => ({ - populateEmojis: jest.fn(), - }), - }, - { - provide: QueueService, useFactory: () => ({ - systemWebhookDeliver: jest.fn(), - userWebhookDeliver: jest.fn(), - }), - }, - { - provide: UserWebhookService, useFactory: () => ({ - fetchWebhooks: jest.fn(), - }), - }, - { - provide: SystemWebhookService, useFactory: () => ({ - fetchSystemWebhooks: jest.fn(), - }), - }, - ], - }).compile(); + }) + .overrideProvider(CustomEmojiService).useValue({ + populateEmojis: jest.fn(), + }) + .overrideProvider(QueueService).useValue({ + systemWebhookDeliver: jest.fn(), + userWebhookDeliver: jest.fn(), + }) + .overrideProvider(UserWebhookService).useValue({ + fetchWebhooks: jest.fn(), + }) + .overrideProvider(SystemWebhookService).useValue({ + fetchSystemWebhooks: jest.fn(), + }) + .compile(); + + await app.init(); + app.enableShutdownHooks(); usersRepository = app.get(DI.usersRepository); userProfilesRepository = app.get(DI.userProfilesRepository); service = app.get(WebhookTestService); idService = app.get(IdService); + cacheManagementService = app.get(CacheManagementService); queueService = app.get(QueueService) as jest.Mocked; userWebhookService = app.get(UserWebhookService) as jest.Mocked; systemWebhookService = app.get(SystemWebhookService) as jest.Mocked; + }); - app.enableShutdownHooks(); + afterAll(async () => { + await app.close(); }); beforeEach(async () => { @@ -111,12 +110,9 @@ describe('WebhookTestService', () => { userWebhookService.fetchWebhooks.mockClear(); systemWebhookService.fetchSystemWebhooks.mockClear(); - await usersRepository.delete({}); await userProfilesRepository.delete({}); - }); - - afterAll(async () => { - await app.close(); + await usersRepository.delete({}); + cacheManagementService.clear(); }); // -------------------------------------------------------------------------------------- diff --git a/packages/backend/test/unit/activitypub.ts b/packages/backend/test/unit/activitypub.ts index b8920fefbb..9e058fc717 100644 --- a/packages/backend/test/unit/activitypub.ts +++ b/packages/backend/test/unit/activitypub.ts @@ -2,19 +2,16 @@ * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ + process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import { generateKeyPair } from 'crypto'; import { Test, TestingModule } from '@nestjs/testing'; import { jest } from '@jest/globals'; - -import { NoOpCacheService } from '../misc/noOpCaches.js'; -import { FakeInternalEventService } from '../misc/FakeInternalEventService.js'; +import { MockLoggerService } from '../misc/MockLoggerService.js'; import type { Config } from '@/config.js'; import type { MiLocalUser, MiRemoteUser } from '@/models/User.js'; -import { InternalEventService } from '@/core/InternalEventService.js'; -import { CacheService } from '@/core/CacheService.js'; import { ApImageService } from '@/core/activitypub/models/ApImageService.js'; import { ApNoteService } from '@/core/activitypub/models/ApNoteService.js'; import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js'; @@ -25,6 +22,8 @@ import { GlobalModule } from '@/GlobalModule.js'; import { CoreModule } from '@/core/CoreModule.js'; import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; import { LoggerService } from '@/core/LoggerService.js'; +import { CacheManagementService } from '@/core/CacheManagementService.js'; +import { ApResolverService } from '@/core/activitypub/ApResolverService.js'; import type { IActor, IApDocument, ICollection, IObject, IPost } from '@/core/activitypub/type.js'; import { MiMeta, MiNote, MiUser, MiUserKeypair, UserProfilesRepository, UserPublickeysRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; @@ -106,6 +105,8 @@ describe('ActivityPub', () => { let userPublickeysRepository: UserPublickeysRepository; let userKeypairService: UserKeypairService; let config: Config; + let cacheManagementService: CacheManagementService; + let mockLoggerService: MockLoggerService; const metaInitial = { id: 'x', @@ -158,9 +159,8 @@ describe('ActivityPub', () => { }; }, }) - .overrideProvider(DI.meta).useFactory({ factory: () => meta }) - .overrideProvider(CacheService).useClass(NoOpCacheService) - .overrideProvider(InternalEventService).useClass(FakeInternalEventService) + .overrideProvider(DI.meta).useValue(meta) + .overrideProvider(LoggerService).useClass(MockLoggerService) .compile(); await app.init(); @@ -178,20 +178,24 @@ describe('ActivityPub', () => { userPublickeysRepository = app.get(DI.userPublickeysRepository); userKeypairService = app.get(UserKeypairService); config = app.get(DI.config); - - // Prevent ApPersonService from fetching instance, as it causes Jest import-after-test error - const federatedInstanceService = app.get(FederatedInstanceService); - jest.spyOn(federatedInstanceService, 'fetch').mockImplementation(() => new Promise(() => { })); - }); - - beforeEach(() => { - resolver.clear(); + cacheManagementService = app.get(CacheManagementService); + mockLoggerService = app.get(LoggerService); + notesRepository = app.get(DI.notesRepository); }); afterAll(async () => { await app.close(); }); + beforeEach(async () => { + // Clear all caches app-wide + cacheManagementService.clear(); + + // Reset mocks + mockLoggerService.reset(); + resolver.clear(); + }); + describe('Parse minimum object', () => { const actor = createRandomActor(); diff --git a/packages/backend/test/unit/entities/UserEntityService.ts b/packages/backend/test/unit/entities/UserEntityService.ts index 3eda3eee01..de335da644 100644 --- a/packages/backend/test/unit/entities/UserEntityService.ts +++ b/packages/backend/test/unit/entities/UserEntityService.ts @@ -4,9 +4,8 @@ */ import { Test, TestingModule } from '@nestjs/testing'; -import { FakeInternalEventService } from '../../misc/FakeInternalEventService.js'; -import { NoOpCacheService } from '../../misc/noOpCaches.js'; import type { MiUser } from '@/models/User.js'; +import { CacheManagementService } from '@/core/CacheManagementService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { GlobalModule } from '@/GlobalModule.js'; import { CoreModule } from '@/core/CoreModule.js'; @@ -21,39 +20,6 @@ import { UsersRepository, } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; -import { AvatarDecorationService } from '@/core/AvatarDecorationService.js'; -import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js'; -import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; -import { PageEntityService } from '@/core/entities/PageEntityService.js'; -import { CustomEmojiService } from '@/core/CustomEmojiService.js'; -import { AnnouncementService } from '@/core/AnnouncementService.js'; -import { RoleService } from '@/core/RoleService.js'; -import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; -import { IdService } from '@/core/IdService.js'; -import { UtilityService } from '@/core/UtilityService.js'; -import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; -import { ModerationLogService } from '@/core/ModerationLogService.js'; -import { GlobalEventService } from '@/core/GlobalEventService.js'; -import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; -import { MetaService } from '@/core/MetaService.js'; -import { FetchInstanceMetadataService } from '@/core/FetchInstanceMetadataService.js'; -import { CacheService } from '@/core/CacheService.js'; -import { ApResolverService } from '@/core/activitypub/ApResolverService.js'; -import { ApNoteService } from '@/core/activitypub/models/ApNoteService.js'; -import { ApImageService } from '@/core/activitypub/models/ApImageService.js'; -import { ApMfmService } from '@/core/activitypub/ApMfmService.js'; -import { MfmService } from '@/core/MfmService.js'; -import { HashtagService } from '@/core/HashtagService.js'; -import UsersChart from '@/core/chart/charts/users.js'; -import { ChartLoggerService } from '@/core/chart/ChartLoggerService.js'; -import InstanceChart from '@/core/chart/charts/instance.js'; -import { ApLoggerService } from '@/core/activitypub/ApLoggerService.js'; -import { AccountMoveService } from '@/core/AccountMoveService.js'; -import { ReactionService } from '@/core/ReactionService.js'; -import { NotificationService } from '@/core/NotificationService.js'; -import { ReactionsBufferingService } from '@/core/ReactionsBufferingService.js'; -import { ChatService } from '@/core/ChatService.js'; -import { InternalEventService } from '@/core/InternalEventService.js'; process.env.NODE_ENV = 'test'; @@ -69,6 +35,7 @@ describe('UserEntityService', () => { let blockingRepository: BlockingsRepository; let mutingRepository: MutingsRepository; let renoteMutingsRepository: RenoteMutingsRepository; + let cacheManagementService: CacheManagementService; async function createUser(userData: Partial = {}, profileData: Partial = {}) { const un = secureRndstr(16); @@ -143,53 +110,11 @@ describe('UserEntityService', () => { } beforeAll(async () => { - const services = [ - UserEntityService, - ApPersonService, - NoteEntityService, - PageEntityService, - CustomEmojiService, - AnnouncementService, - RoleService, - FederatedInstanceService, - IdService, - AvatarDecorationService, - UtilityService, - EmojiEntityService, - ModerationLogService, - GlobalEventService, - DriveFileEntityService, - MetaService, - FetchInstanceMetadataService, - CacheService, - ApResolverService, - ApNoteService, - ApImageService, - ApMfmService, - MfmService, - HashtagService, - UsersChart, - ChartLoggerService, - InstanceChart, - ApLoggerService, - AccountMoveService, - ReactionService, - ReactionsBufferingService, - NotificationService, - ChatService, - InternalEventService, - ]; - app = await Test.createTestingModule({ imports: [GlobalModule, CoreModule], - providers: [ - ...services, - ...services.map(x => ({ provide: x.name, useExisting: x })), - ], }) - .overrideProvider(InternalEventService).useClass(FakeInternalEventService) - .overrideProvider(CacheService).useClass(NoOpCacheService) .compile(); + await app.init(); app.enableShutdownHooks(); @@ -202,12 +127,25 @@ describe('UserEntityService', () => { blockingRepository = app.get(DI.blockingsRepository); mutingRepository = app.get(DI.mutingsRepository); renoteMutingsRepository = app.get(DI.renoteMutingsRepository); + cacheManagementService = app.get(CacheManagementService); }); afterAll(async () => { await app.close(); }); + afterEach(async () => { + await userProfileRepository.delete({}); + await userMemosRepository.delete({}); + await followingRepository.delete({}); + await followingRequestRepository.delete({}); + await blockingRepository.delete({}); + await mutingRepository.delete({}); + await renoteMutingsRepository.delete({}); + await usersRepository.delete({}); + cacheManagementService.clear(); + }); + test('UserLite', async() => { const me = await createUser(); const who = await createUser();