mirror of
				https://codeberg.org/yeentown/barkey.git
				synced 2025-10-25 18:54:52 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			281 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /*
 | |
|  * SPDX-FileCopyrightText: syuilo and misskey-project
 | |
|  * SPDX-License-Identifier: AGPL-3.0-only
 | |
|  */
 | |
| 
 | |
| import { Test, TestingModule } from '@nestjs/testing';
 | |
| import { describe, jest, test } from '@jest/globals';
 | |
| import { In } from 'typeorm';
 | |
| import { UserSearchService } from '@/core/UserSearchService.js';
 | |
| import { FollowingsRepository, InstancesRepository, MiUser, UserProfilesRepository, UsersRepository } from '@/models/_.js';
 | |
| import { IdService } from '@/core/IdService.js';
 | |
| import { GlobalModule } from '@/GlobalModule.js';
 | |
| import { DI } from '@/di-symbols.js';
 | |
| import { UserEntityService } from '@/core/entities/UserEntityService.js';
 | |
| import { genAidx } from '@/misc/id/aidx.js';
 | |
| 
 | |
| describe('UserSearchService', () => {
 | |
| 	let app: TestingModule;
 | |
| 	let service: UserSearchService;
 | |
| 
 | |
| 	let instancesRepository: InstancesRepository;
 | |
| 	let usersRepository: UsersRepository;
 | |
| 	let followingsRepository: FollowingsRepository;
 | |
| 	let idService: IdService;
 | |
| 	let userProfilesRepository: UserProfilesRepository;
 | |
| 
 | |
| 	let root: MiUser;
 | |
| 	let alice: MiUser;
 | |
| 	let alyce: MiUser;
 | |
| 	let alycia: MiUser;
 | |
| 	let alysha: MiUser;
 | |
| 	let alyson: MiUser;
 | |
| 	let alyssa: MiUser;
 | |
| 	let bob: MiUser;
 | |
| 	let bobbi: MiUser;
 | |
| 	let bobbie: MiUser;
 | |
| 	let bobby: MiUser;
 | |
| 
 | |
| 	async function createUser(data: Partial<MiUser> = {}) {
 | |
| 		if (data.host != null) {
 | |
| 			await instancesRepository
 | |
| 				.createQueryBuilder('instance')
 | |
| 				.insert()
 | |
| 				.values({
 | |
| 					id: genAidx(Date.now()),
 | |
| 					firstRetrievedAt: new Date(),
 | |
| 					host: data.host,
 | |
| 				})
 | |
| 				.orIgnore()
 | |
| 				.execute();
 | |
| 		}
 | |
| 
 | |
| 		const user = await usersRepository
 | |
| 			.insert({
 | |
| 				id: idService.gen(),
 | |
| 				...data,
 | |
| 			})
 | |
| 			.then(x => usersRepository.findOneByOrFail(x.identifiers[0]));
 | |
| 
 | |
| 		await userProfilesRepository.insert({
 | |
| 			userId: user.id,
 | |
| 		});
 | |
| 
 | |
| 		return user;
 | |
| 	}
 | |
| 
 | |
| 	async function createFollowings(follower: MiUser, followees: MiUser[]) {
 | |
| 		for (const followee of followees) {
 | |
| 			await followingsRepository.insert({
 | |
| 				id: idService.gen(),
 | |
| 				followerId: follower.id,
 | |
| 				followeeId: followee.id,
 | |
| 			});
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	async function setActive(users: MiUser[]) {
 | |
| 		for (const user of users) {
 | |
| 			await usersRepository.update(user.id, {
 | |
| 				updatedAt: new Date(),
 | |
| 			});
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	async function setInactive(users: MiUser[]) {
 | |
| 		for (const user of users) {
 | |
| 			await usersRepository.update(user.id, {
 | |
| 				updatedAt: new Date(0),
 | |
| 			});
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	async function setSuspended(users: MiUser[]) {
 | |
| 		for (const user of users) {
 | |
| 			await usersRepository.update(user.id, {
 | |
| 				isSuspended: true,
 | |
| 			});
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	beforeAll(async () => {
 | |
| 		app = await Test
 | |
| 			.createTestingModule({
 | |
| 				imports: [
 | |
| 					GlobalModule,
 | |
| 				],
 | |
| 				providers: [
 | |
| 					UserSearchService,
 | |
| 					{
 | |
| 						provide: UserEntityService, useFactory: jest.fn(() => ({
 | |
| 							// とりあえずIDが返れば確認が出来るので
 | |
| 							packMany: (value: any) => value,
 | |
| 						})),
 | |
| 					},
 | |
| 					IdService,
 | |
| 				],
 | |
| 			})
 | |
| 			.compile();
 | |
| 
 | |
| 		await app.init();
 | |
| 
 | |
| 		instancesRepository = app.get<InstancesRepository>(DI.instancesRepository);
 | |
| 		usersRepository = app.get(DI.usersRepository);
 | |
| 		userProfilesRepository = app.get(DI.userProfilesRepository);
 | |
| 		followingsRepository = app.get(DI.followingsRepository);
 | |
| 
 | |
| 		service = app.get(UserSearchService);
 | |
| 		idService = app.get(IdService);
 | |
| 	});
 | |
| 
 | |
| 	beforeEach(async () => {
 | |
| 		root = await createUser({ username: 'root', usernameLower: 'root' });
 | |
| 		alice = await createUser({ username: 'Alice', usernameLower: 'alice' });
 | |
| 		alyce = await createUser({ username: 'Alyce', usernameLower: 'alyce' });
 | |
| 		alycia = await createUser({ username: 'Alycia', usernameLower: 'alycia' });
 | |
| 		alysha = await createUser({ username: 'Alysha', usernameLower: 'alysha' });
 | |
| 		alyson = await createUser({ username: 'Alyson', usernameLower: 'alyson', host: 'example.com' });
 | |
| 		alyssa = await createUser({ username: 'Alyssa', usernameLower: 'alyssa', host: 'example.com' });
 | |
| 		bob = await createUser({ username: 'Bob', usernameLower: 'bob' });
 | |
| 		bobbi = await createUser({ username: 'Bobbi', usernameLower: 'bobbi' });
 | |
| 		bobbie = await createUser({ username: 'Bobbie', usernameLower: 'bobbie', host: 'example.com' });
 | |
| 		bobby = await createUser({ username: 'Bobby', usernameLower: 'bobby', host: 'example.com' });
 | |
| 	});
 | |
| 
 | |
| 	afterEach(async () => {
 | |
| 		await usersRepository.delete({});
 | |
| 	});
 | |
| 
 | |
| 	afterAll(async () => {
 | |
| 		await app.close();
 | |
| 	});
 | |
| 
 | |
| 	describe('searchByUsernameAndHost', () => {
 | |
| 		test('フォロー中のアクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => {
 | |
| 			await createFollowings(root, [alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
 | |
| 			await setActive([alice, alyce, alyssa, bob, bobbi, bobbie, bobby]);
 | |
| 			await setInactive([alycia, alysha, alyson]);
 | |
| 
 | |
| 			const result = await service.searchByUsernameAndHost(
 | |
| 				{ username: 'al' },
 | |
| 				{ limit: 100 },
 | |
| 				root,
 | |
| 			);
 | |
| 
 | |
| 			// alycia, alysha, alysonは非アクティブなので後ろに行く
 | |
| 			expect(result).toEqual([alice, alyce, alyssa, alycia, alysha, alyson].map(x => x.id));
 | |
| 		});
 | |
| 
 | |
| 		test('フォロー中の非アクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => {
 | |
| 			await createFollowings(root, [alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
 | |
| 			await setInactive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
 | |
| 
 | |
| 			const result = await service.searchByUsernameAndHost(
 | |
| 				{ username: 'al' },
 | |
| 				{ limit: 100 },
 | |
| 				root,
 | |
| 			);
 | |
| 
 | |
| 			// alice, alyceはフォローしていないので後ろに行く
 | |
| 			expect(result).toEqual([alycia, alysha, alyson, alyssa, alice, alyce].map(x => x.id));
 | |
| 		});
 | |
| 
 | |
| 		test('フォローしていないアクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => {
 | |
| 			await setActive([alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
 | |
| 			await setInactive([alice, alyce, alycia]);
 | |
| 
 | |
| 			const result = await service.searchByUsernameAndHost(
 | |
| 				{ username: 'al' },
 | |
| 				{ limit: 100 },
 | |
| 				root,
 | |
| 			);
 | |
| 
 | |
| 			// alice, alyce, alyciaは非アクティブなので後ろに行く
 | |
| 			expect(result).toEqual([alysha, alyson, alyssa, alice, alyce, alycia].map(x => x.id));
 | |
| 		});
 | |
| 
 | |
| 		test('フォローしていない非アクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => {
 | |
| 			await setInactive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
 | |
| 
 | |
| 			const result = await service.searchByUsernameAndHost(
 | |
| 				{ username: 'al' },
 | |
| 				{ limit: 100 },
 | |
| 				root,
 | |
| 			);
 | |
| 
 | |
| 			expect(result).toEqual([alice, alyce, alycia, alysha, alyson, alyssa].map(x => x.id));
 | |
| 		});
 | |
| 
 | |
| 		test('フォロー(アクティブ)、フォロー(非アクティブ)、非フォロー(アクティブ)、非フォロー(非アクティブ)混在時の優先順位度確認', async () => {
 | |
| 			await createFollowings(root, [alyson, alyssa, bob, bobbi, bobbie]);
 | |
| 			await setActive([root, alyssa, bob, bobbi, alyce, alycia]);
 | |
| 			await setInactive([alyson, alice, alysha, bobbie, bobby]);
 | |
| 
 | |
| 			const result = await service.searchByUsernameAndHost(
 | |
| 				{ },
 | |
| 				{ limit: 100 },
 | |
| 				root,
 | |
| 			);
 | |
| 
 | |
| 			// 見る用
 | |
| 			// const users = await usersRepository.findBy({ id: In(result) }).then(it => new Map(it.map(x => [x.id, x])));
 | |
| 			// console.log(result.map(x => users.get(x as any)).map(it => it?.username));
 | |
| 
 | |
| 			// フォローしててアクティブなので先頭: alyssa, bob, bobbi
 | |
| 			// フォローしてて非アクティブなので次: alyson, bobbie
 | |
| 			// フォローしてないけどアクティブなので次: alyce, alycia, root(アルファベット順的にここになる)
 | |
| 			// フォローしてないし非アクティブなので最後: alice, alysha, bobby
 | |
| 			expect(result).toEqual([alyssa, bob, bobbi, alyson, bobbie, alyce, alycia, root, alice, alysha, bobby].map(x => x.id));
 | |
| 		});
 | |
| 
 | |
| 		test('[非ログイン] アクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => {
 | |
| 			await setActive([alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
 | |
| 			await setInactive([alice, alyce, alycia]);
 | |
| 
 | |
| 			const result = await service.searchByUsernameAndHost(
 | |
| 				{ username: 'al' },
 | |
| 				{ limit: 100 },
 | |
| 			);
 | |
| 
 | |
| 			// alice, alyce, alyciaは非アクティブなので後ろに行く
 | |
| 			expect(result).toEqual([alysha, alyson, alyssa, alice, alyce, alycia].map(x => x.id));
 | |
| 		});
 | |
| 
 | |
| 		test('[非ログイン] 非アクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => {
 | |
| 			await setInactive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
 | |
| 
 | |
| 			const result = await service.searchByUsernameAndHost(
 | |
| 				{ username: 'al' },
 | |
| 				{ limit: 100 },
 | |
| 			);
 | |
| 
 | |
| 			expect(result).toEqual([alice, alyce, alycia, alysha, alyson, alyssa].map(x => x.id));
 | |
| 		});
 | |
| 
 | |
| 		test('フォロー中のアクティブユーザのうち、"al"から始まり"example.com"にいる人が全員ヒットする', async () => {
 | |
| 			await createFollowings(root, [alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
 | |
| 			await setActive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
 | |
| 
 | |
| 			const result = await service.searchByUsernameAndHost(
 | |
| 				{ username: 'al', host: 'exam' },
 | |
| 				{ limit: 100 },
 | |
| 				root,
 | |
| 			);
 | |
| 
 | |
| 			expect(result).toEqual([alyson, alyssa].map(x => x.id));
 | |
| 		});
 | |
| 
 | |
| 		test('サスペンド済みユーザは出ない', async () => {
 | |
| 			await setActive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
 | |
| 			await setSuspended([alice, alyce, alycia]);
 | |
| 
 | |
| 			const result = await service.searchByUsernameAndHost(
 | |
| 				{ username: 'al' },
 | |
| 				{ limit: 100 },
 | |
| 				root,
 | |
| 			);
 | |
| 
 | |
| 			expect(result).toEqual([alysha, alyson, alyssa].map(x => x.id));
 | |
| 		});
 | |
| 	});
 | |
| });
 |