Merge branch 'develop' into remote-public-reactions

This commit is contained in:
Daiki Mizukami 2024-10-03 21:49:52 +09:00
commit 97f96ab92d
No known key found for this signature in database
GPG key ID: 10478E598B944AA2
618 changed files with 22316 additions and 8731 deletions

View file

@ -13,6 +13,7 @@ import * as lolex from '@sinonjs/fake-timers';
import { GlobalModule } from '@/GlobalModule.js';
import { RoleService } from '@/core/RoleService.js';
import {
MiMeta,
MiRole,
MiRoleAssignment,
MiUser,
@ -41,7 +42,7 @@ describe('RoleService', () => {
let usersRepository: UsersRepository;
let rolesRepository: RolesRepository;
let roleAssignmentsRepository: RoleAssignmentsRepository;
let metaService: jest.Mocked<MetaService>;
let meta: jest.Mocked<MiMeta>;
let notificationService: jest.Mocked<NotificationService>;
let clock: lolex.InstalledClock;
@ -142,7 +143,7 @@ describe('RoleService', () => {
rolesRepository = app.get<RolesRepository>(DI.rolesRepository);
roleAssignmentsRepository = app.get<RoleAssignmentsRepository>(DI.roleAssignmentsRepository);
metaService = app.get<MetaService>(MetaService) as jest.Mocked<MetaService>;
meta = app.get<MiMeta>(DI.meta) as jest.Mocked<MiMeta>;
notificationService = app.get<NotificationService>(NotificationService) as jest.Mocked<NotificationService>;
await roleService.onModuleInit();
@ -164,11 +165,9 @@ describe('RoleService', () => {
describe('getUserPolicies', () => {
test('instance default policies', async () => {
const user = await createUser();
metaService.fetch.mockResolvedValue({
policies: {
canManageCustomEmojis: false,
},
} as any);
meta.policies = {
canManageCustomEmojis: false,
};
const result = await roleService.getUserPolicies(user.id);
@ -177,11 +176,9 @@ describe('RoleService', () => {
test('instance default policies 2', async () => {
const user = await createUser();
metaService.fetch.mockResolvedValue({
policies: {
canManageCustomEmojis: true,
},
} as any);
meta.policies = {
canManageCustomEmojis: true,
};
const result = await roleService.getUserPolicies(user.id);
@ -201,11 +198,9 @@ describe('RoleService', () => {
},
});
await roleService.assign(user.id, role.id);
metaService.fetch.mockResolvedValue({
policies: {
canManageCustomEmojis: false,
},
} as any);
meta.policies = {
canManageCustomEmojis: false,
};
const result = await roleService.getUserPolicies(user.id);
@ -236,11 +231,9 @@ describe('RoleService', () => {
});
await roleService.assign(user.id, role1.id);
await roleService.assign(user.id, role2.id);
metaService.fetch.mockResolvedValue({
policies: {
driveCapacityMb: 50,
},
} as any);
meta.policies = {
driveCapacityMb: 50,
};
const result = await roleService.getUserPolicies(user.id);
@ -260,11 +253,9 @@ describe('RoleService', () => {
},
});
await roleService.assign(user.id, role.id, new Date(Date.now() + (1000 * 60 * 60 * 24)));
metaService.fetch.mockResolvedValue({
policies: {
canManageCustomEmojis: false,
},
} as any);
meta.policies = {
canManageCustomEmojis: false,
};
const result = await roleService.getUserPolicies(user.id);
expect(result.canManageCustomEmojis).toBe(true);

View file

@ -0,0 +1,182 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { IncomingHttpHeaders } from 'node:http';
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, jest, test } from '@jest/globals';
import { Test, TestingModule } from '@nestjs/testing';
import { FastifyReply, FastifyRequest } from 'fastify';
import { AuthenticationResponseJSON } from '@simplewebauthn/types';
import { HttpHeader } from 'fastify/types/utils.js';
import { MockFunctionMetadata, ModuleMocker } from 'jest-mock';
import { MiUser } from '@/models/User.js';
import { MiUserProfile, UserProfilesRepository, UsersRepository } from '@/models/_.js';
import { IdService } from '@/core/IdService.js';
import { GlobalModule } from '@/GlobalModule.js';
import { DI } from '@/di-symbols.js';
import { CoreModule } from '@/core/CoreModule.js';
import { SigninWithPasskeyApiService } from '@/server/api/SigninWithPasskeyApiService.js';
import { RateLimiterService } from '@/server/api/RateLimiterService.js';
import { WebAuthnService } from '@/core/WebAuthnService.js';
import { SigninService } from '@/server/api/SigninService.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
const moduleMocker = new ModuleMocker(global);
class FakeLimiter {
public async limit() {
return;
}
}
class FakeSigninService {
public signin(..._args: any): any {
return true;
}
}
class DummyFastifyReply {
public statusCode: number;
code(num: number): void {
this.statusCode = num;
}
header(_key: HttpHeader, _value: any): void {
}
}
class DummyFastifyRequest {
public ip: string;
public body: {credential: any, context: string};
public headers: IncomingHttpHeaders = { 'accept': 'application/json' };
constructor(body?: any) {
this.ip = '0.0.0.0';
this.body = body;
}
}
type ApiFastifyRequestType = FastifyRequest<{
Body: {
credential?: AuthenticationResponseJSON;
context?: string;
};
}>;
describe('SigninWithPasskeyApiService', () => {
let app: TestingModule;
let passkeyApiService: SigninWithPasskeyApiService;
let usersRepository: UsersRepository;
let userProfilesRepository: UserProfilesRepository;
let webAuthnService: WebAuthnService;
let idService: IdService;
let FakeWebauthnVerify: ()=>Promise<string>;
async function createUser(data: Partial<MiUser> = {}) {
const user = await usersRepository
.save({
...data,
});
return user;
}
async function createUserProfile(data: Partial<MiUserProfile> = {}) {
const userProfile = await userProfilesRepository
.save({ ...data },
);
return userProfile;
}
beforeAll(async () => {
app = await Test.createTestingModule({
imports: [GlobalModule, CoreModule],
providers: [
SigninWithPasskeyApiService,
{ provide: RateLimiterService, useClass: FakeLimiter },
{ provide: SigninService, useClass: FakeSigninService },
],
}).useMocker((token) => {
if (typeof token === 'function') {
const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata<any, any>;
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
return new Mock();
}
}).compile();
passkeyApiService = app.get<SigninWithPasskeyApiService>(SigninWithPasskeyApiService);
usersRepository = app.get<UsersRepository>(DI.usersRepository);
userProfilesRepository = app.get<UserProfilesRepository>(DI.userProfilesRepository);
webAuthnService = app.get<WebAuthnService>(WebAuthnService);
idService = app.get<IdService>(IdService);
});
beforeEach(async () => {
const uid = idService.gen();
FakeWebauthnVerify = async () => {
return uid;
};
jest.spyOn(webAuthnService, 'verifySignInWithPasskeyAuthentication').mockImplementation(FakeWebauthnVerify);
const dummyUser = {
id: uid, username: uid, usernameLower: uid.toLocaleLowerCase(), uri: null, host: null,
};
const dummyProfile = {
userId: uid,
password: 'qwerty',
usePasswordLessLogin: true,
};
await createUser(dummyUser);
await createUserProfile(dummyProfile);
});
afterAll(async () => {
await app.close();
});
describe('Get Passkey Options', () => {
it('Should return passkey Auth Options', async () => {
const req = new DummyFastifyRequest({}) as ApiFastifyRequestType;
const res = new DummyFastifyReply() as unknown as FastifyReply;
const res_body = await passkeyApiService.signin(req, res);
expect(res.statusCode).toBe(200);
expect((res_body as any).option).toBeDefined();
expect(typeof (res_body as any).context).toBe('string');
});
});
describe('Try Passkey Auth', () => {
it('Should Success', async () => {
const req = new DummyFastifyRequest({ context: 'auth-context', credential: { dummy: [] } }) as ApiFastifyRequestType;
const res = new DummyFastifyReply() as FastifyReply;
const res_body = await passkeyApiService.signin(req, res);
expect((res_body as any).signinResponse).toBeDefined();
});
it('Should return 400 Without Auth Context', async () => {
const req = new DummyFastifyRequest({ credential: { dummy: [] } }) as ApiFastifyRequestType;
const res = new DummyFastifyReply() as FastifyReply;
const res_body = await passkeyApiService.signin(req, res);
expect(res.statusCode).toBe(400);
expect((res_body as any).error?.id).toStrictEqual('1658cc2e-4495-461f-aee4-d403cdf073c1');
});
it('Should return 403 When Challenge Verify fail', async () => {
const req = new DummyFastifyRequest({ context: 'misskey-1234', credential: { dummy: [] } }) as ApiFastifyRequestType;
const res = new DummyFastifyReply() as FastifyReply;
jest.spyOn(webAuthnService, 'verifySignInWithPasskeyAuthentication')
.mockImplementation(async () => {
throw new IdentifiableError('THIS_ERROR_CODE_SHOULD_BE_FORWARDED');
});
const res_body = await passkeyApiService.signin(req, res);
expect(res.statusCode).toBe(403);
expect((res_body as any).error?.id).toStrictEqual('THIS_ERROR_CODE_SHOULD_BE_FORWARDED');
});
it('Should return 403 When The user not Enabled Passwordless login', async () => {
const req = new DummyFastifyRequest({ context: 'misskey-1234', credential: { dummy: [] } }) as ApiFastifyRequestType;
const res = new DummyFastifyReply() as FastifyReply;
const userId = await FakeWebauthnVerify();
const data = { userId: userId, usePasswordLessLogin: false };
await userProfilesRepository.update({ userId: userId }, data);
const res_body = await passkeyApiService.signin(req, res);
expect(res.statusCode).toBe(403);
expect((res_body as any).error?.id).toStrictEqual('2d84773e-f7b7-4d0b-8f72-bb69b584c912');
});
});
});

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
@ -6,6 +7,7 @@
import { setTimeout } from 'node:timers/promises';
import { afterEach, beforeEach, describe, expect, jest } from '@jest/globals';
import { Test, TestingModule } from '@nestjs/testing';
import { randomString } from '../utils.js';
import { MiUser } from '@/models/User.js';
import { MiSystemWebhook, SystemWebhookEventType } from '@/models/SystemWebhook.js';
import { SystemWebhooksRepository, UsersRepository } from '@/models/_.js';
@ -17,7 +19,6 @@ 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 { randomString } from '../utils.js';
describe('SystemWebhookService', () => {
let app: TestingModule;
@ -313,7 +314,7 @@ describe('SystemWebhookService', () => {
isActive: true,
on: ['abuseReport'],
});
await service.enqueueSystemWebhook(webhook.id, 'abuseReport', { foo: 'bar' });
await service.enqueueSystemWebhook(webhook.id, 'abuseReport', { foo: 'bar' } as any);
expect(queueService.systemWebhookDeliver).toHaveBeenCalled();
});
@ -323,7 +324,7 @@ describe('SystemWebhookService', () => {
isActive: false,
on: ['abuseReport'],
});
await service.enqueueSystemWebhook(webhook.id, 'abuseReport', { foo: 'bar' });
await service.enqueueSystemWebhook(webhook.id, 'abuseReport', { foo: 'bar' } as any);
expect(queueService.systemWebhookDeliver).not.toHaveBeenCalled();
});
@ -337,8 +338,8 @@ describe('SystemWebhookService', () => {
isActive: true,
on: ['abuseReportResolved'],
});
await service.enqueueSystemWebhook(webhook1.id, 'abuseReport', { foo: 'bar' });
await service.enqueueSystemWebhook(webhook2.id, 'abuseReport', { foo: 'bar' });
await service.enqueueSystemWebhook(webhook1.id, 'abuseReport', { foo: 'bar' } as any);
await service.enqueueSystemWebhook(webhook2.id, 'abuseReport', { foo: 'bar' } as any);
expect(queueService.systemWebhookDeliver).not.toHaveBeenCalled();
});

View file

@ -0,0 +1,245 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { afterEach, beforeEach, describe, expect, jest } from '@jest/globals';
import { Test, TestingModule } from '@nestjs/testing';
import { randomString } from '../utils.js';
import { MiUser } from '@/models/User.js';
import { MiWebhook, UsersRepository, WebhooksRepository } from '@/models/_.js';
import { IdService } from '@/core/IdService.js';
import { GlobalModule } from '@/GlobalModule.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { DI } from '@/di-symbols.js';
import { QueueService } from '@/core/QueueService.js';
import { LoggerService } from '@/core/LoggerService.js';
import { UserWebhookService } from '@/core/UserWebhookService.js';
describe('UserWebhookService', () => {
let app: TestingModule;
let service: UserWebhookService;
// --------------------------------------------------------------------------------------
let usersRepository: UsersRepository;
let userWebhooksRepository: WebhooksRepository;
let idService: IdService;
let queueService: jest.Mocked<QueueService>;
// --------------------------------------------------------------------------------------
let root: MiUser;
// --------------------------------------------------------------------------------------
async function createUser(data: Partial<MiUser> = {}) {
return await usersRepository
.insert({
id: idService.gen(),
...data,
})
.then(x => usersRepository.findOneByOrFail(x.identifiers[0]));
}
async function createWebhook(data: Partial<MiWebhook> = {}) {
return userWebhooksRepository
.insert({
id: idService.gen(),
name: randomString(),
on: ['mention'],
url: 'https://example.com',
secret: randomString(),
userId: root.id,
...data,
})
.then(x => userWebhooksRepository.findOneByOrFail(x.identifiers[0]));
}
// --------------------------------------------------------------------------------------
async function beforeAllImpl() {
app = await Test
.createTestingModule({
imports: [
GlobalModule,
],
providers: [
UserWebhookService,
IdService,
LoggerService,
GlobalEventService,
{
provide: QueueService, useFactory: () => ({ systemWebhookDeliver: jest.fn() }),
},
],
})
.compile();
usersRepository = app.get(DI.usersRepository);
userWebhooksRepository = app.get(DI.webhooksRepository);
service = app.get(UserWebhookService);
idService = app.get(IdService);
queueService = app.get(QueueService) as jest.Mocked<QueueService>;
app.enableShutdownHooks();
}
async function afterAllImpl() {
await app.close();
}
async function beforeEachImpl() {
root = await createUser({ isRoot: true, username: 'root', usernameLower: 'root' });
}
async function afterEachImpl() {
await usersRepository.delete({});
await userWebhooksRepository.delete({});
}
// --------------------------------------------------------------------------------------
describe('アプリを毎回作り直す必要のないグループ', () => {
beforeAll(beforeAllImpl);
afterAll(afterAllImpl);
beforeEach(beforeEachImpl);
afterEach(afterEachImpl);
describe('fetchSystemWebhooks', () => {
test('フィルタなし', async () => {
const webhook1 = await createWebhook({
active: true,
on: ['mention'],
});
const webhook2 = await createWebhook({
active: false,
on: ['mention'],
});
const webhook3 = await createWebhook({
active: true,
on: ['reply'],
});
const webhook4 = await createWebhook({
active: false,
on: [],
});
const fetchedWebhooks = await service.fetchWebhooks();
expect(fetchedWebhooks).toEqual([webhook1, webhook2, webhook3, webhook4]);
});
test('activeのみ', async () => {
const webhook1 = await createWebhook({
active: true,
on: ['mention'],
});
const webhook2 = await createWebhook({
active: false,
on: ['mention'],
});
const webhook3 = await createWebhook({
active: true,
on: ['reply'],
});
const webhook4 = await createWebhook({
active: false,
on: [],
});
const fetchedWebhooks = await service.fetchWebhooks({ isActive: true });
expect(fetchedWebhooks).toEqual([webhook1, webhook3]);
});
test('特定のイベントのみ', async () => {
const webhook1 = await createWebhook({
active: true,
on: ['mention'],
});
const webhook2 = await createWebhook({
active: false,
on: ['mention'],
});
const webhook3 = await createWebhook({
active: true,
on: ['reply'],
});
const webhook4 = await createWebhook({
active: false,
on: [],
});
const fetchedWebhooks = await service.fetchWebhooks({ on: ['mention'] });
expect(fetchedWebhooks).toEqual([webhook1, webhook2]);
});
test('activeな特定のイベントのみ', async () => {
const webhook1 = await createWebhook({
active: true,
on: ['mention'],
});
const webhook2 = await createWebhook({
active: false,
on: ['mention'],
});
const webhook3 = await createWebhook({
active: true,
on: ['reply'],
});
const webhook4 = await createWebhook({
active: false,
on: [],
});
const fetchedWebhooks = await service.fetchWebhooks({ on: ['mention'], isActive: true });
expect(fetchedWebhooks).toEqual([webhook1]);
});
test('ID指定', async () => {
const webhook1 = await createWebhook({
active: true,
on: ['mention'],
});
const webhook2 = await createWebhook({
active: false,
on: ['mention'],
});
const webhook3 = await createWebhook({
active: true,
on: ['reply'],
});
const webhook4 = await createWebhook({
active: false,
on: [],
});
const fetchedWebhooks = await service.fetchWebhooks({ ids: [webhook1.id, webhook4.id] });
expect(fetchedWebhooks).toEqual([webhook1, webhook4]);
});
test('ID指定(他条件とANDになるか見たい)', async () => {
const webhook1 = await createWebhook({
active: true,
on: ['mention'],
});
const webhook2 = await createWebhook({
active: false,
on: ['mention'],
});
const webhook3 = await createWebhook({
active: true,
on: ['reply'],
});
const webhook4 = await createWebhook({
active: false,
on: [],
});
const fetchedWebhooks = await service.fetchWebhooks({ ids: [webhook1.id, webhook4.id], isActive: false });
expect(fetchedWebhooks).toEqual([webhook4]);
});
});
});
});

View file

@ -0,0 +1,225 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Test, TestingModule } from '@nestjs/testing';
import { beforeAll, describe, jest } from '@jest/globals';
import { WebhookTestService } from '@/core/WebhookTestService.js';
import { UserWebhookService } from '@/core/UserWebhookService.js';
import { SystemWebhookService } from '@/core/SystemWebhookService.js';
import { GlobalModule } from '@/GlobalModule.js';
import { MiSystemWebhook, MiUser, MiWebhook, UserProfilesRepository, UsersRepository } from '@/models/_.js';
import { IdService } from '@/core/IdService.js';
import { DI } from '@/di-symbols.js';
import { QueueService } from '@/core/QueueService.js';
describe('WebhookTestService', () => {
let app: TestingModule;
let service: WebhookTestService;
// --------------------------------------------------------------------------------------
let usersRepository: UsersRepository;
let userProfilesRepository: UserProfilesRepository;
let queueService: jest.Mocked<QueueService>;
let userWebhookService: jest.Mocked<UserWebhookService>;
let systemWebhookService: jest.Mocked<SystemWebhookService>;
let idService: IdService;
let root: MiUser;
let alice: MiUser;
async function createUser(data: Partial<MiUser> = {}) {
const user = await usersRepository
.insert({
id: idService.gen(),
...data,
})
.then(x => usersRepository.findOneByOrFail(x.identifiers[0]));
await userProfilesRepository.insert({
userId: user.id,
});
return user;
}
// --------------------------------------------------------------------------------------
beforeAll(async () => {
app = await Test.createTestingModule({
imports: [
GlobalModule,
],
providers: [
WebhookTestService,
IdService,
{
provide: QueueService, useFactory: () => ({
systemWebhookDeliver: jest.fn(),
userWebhookDeliver: jest.fn(),
}),
},
{
provide: UserWebhookService, useFactory: () => ({
fetchWebhooks: jest.fn(),
}),
},
{
provide: SystemWebhookService, useFactory: () => ({
fetchSystemWebhooks: jest.fn(),
}),
},
],
}).compile();
usersRepository = app.get(DI.usersRepository);
userProfilesRepository = app.get(DI.userProfilesRepository);
service = app.get(WebhookTestService);
idService = app.get(IdService);
queueService = app.get(QueueService) as jest.Mocked<QueueService>;
userWebhookService = app.get(UserWebhookService) as jest.Mocked<UserWebhookService>;
systemWebhookService = app.get(SystemWebhookService) as jest.Mocked<SystemWebhookService>;
app.enableShutdownHooks();
});
beforeEach(async () => {
root = await createUser({ username: 'root', usernameLower: 'root', isRoot: true });
alice = await createUser({ username: 'alice', usernameLower: 'alice', isRoot: false });
userWebhookService.fetchWebhooks.mockReturnValue(Promise.resolve([
{ id: 'dummy-webhook', active: true, userId: alice.id } as MiWebhook,
]));
systemWebhookService.fetchSystemWebhooks.mockReturnValue(Promise.resolve([
{ id: 'dummy-webhook', isActive: true } as MiSystemWebhook,
]));
});
afterEach(async () => {
queueService.systemWebhookDeliver.mockClear();
queueService.userWebhookDeliver.mockClear();
userWebhookService.fetchWebhooks.mockClear();
systemWebhookService.fetchSystemWebhooks.mockClear();
await usersRepository.delete({});
await userProfilesRepository.delete({});
});
afterAll(async () => {
await app.close();
});
// --------------------------------------------------------------------------------------
describe('testUserWebhook', () => {
test('note', async () => {
await service.testUserWebhook({ webhookId: 'dummy-webhook', type: 'note' }, alice);
const calls = queueService.userWebhookDeliver.mock.calls[0];
expect((calls[0] as any).id).toBe('dummy-webhook');
expect(calls[1]).toBe('note');
expect((calls[2] as any).id).toBe('dummy-note-1');
});
test('reply', async () => {
await service.testUserWebhook({ webhookId: 'dummy-webhook', type: 'reply' }, alice);
const calls = queueService.userWebhookDeliver.mock.calls[0];
expect((calls[0] as any).id).toBe('dummy-webhook');
expect(calls[1]).toBe('reply');
expect((calls[2] as any).id).toBe('dummy-reply-1');
});
test('renote', async () => {
await service.testUserWebhook({ webhookId: 'dummy-webhook', type: 'renote' }, alice);
const calls = queueService.userWebhookDeliver.mock.calls[0];
expect((calls[0] as any).id).toBe('dummy-webhook');
expect(calls[1]).toBe('renote');
expect((calls[2] as any).id).toBe('dummy-renote-1');
});
test('mention', async () => {
await service.testUserWebhook({ webhookId: 'dummy-webhook', type: 'mention' }, alice);
const calls = queueService.userWebhookDeliver.mock.calls[0];
expect((calls[0] as any).id).toBe('dummy-webhook');
expect(calls[1]).toBe('mention');
expect((calls[2] as any).id).toBe('dummy-mention-1');
});
test('follow', async () => {
await service.testUserWebhook({ webhookId: 'dummy-webhook', type: 'follow' }, alice);
const calls = queueService.userWebhookDeliver.mock.calls[0];
expect((calls[0] as any).id).toBe('dummy-webhook');
expect(calls[1]).toBe('follow');
expect((calls[2] as any).id).toBe('dummy-user-1');
});
test('followed', async () => {
await service.testUserWebhook({ webhookId: 'dummy-webhook', type: 'followed' }, alice);
const calls = queueService.userWebhookDeliver.mock.calls[0];
expect((calls[0] as any).id).toBe('dummy-webhook');
expect(calls[1]).toBe('followed');
expect((calls[2] as any).id).toBe('dummy-user-2');
});
test('unfollow', async () => {
await service.testUserWebhook({ webhookId: 'dummy-webhook', type: 'unfollow' }, alice);
const calls = queueService.userWebhookDeliver.mock.calls[0];
expect((calls[0] as any).id).toBe('dummy-webhook');
expect(calls[1]).toBe('unfollow');
expect((calls[2] as any).id).toBe('dummy-user-3');
});
describe('NoSuchWebhookError', () => {
test('user not match', async () => {
userWebhookService.fetchWebhooks.mockClear();
userWebhookService.fetchWebhooks.mockReturnValue(Promise.resolve([
{ id: 'dummy-webhook', active: true } as MiWebhook,
]));
await expect(service.testUserWebhook({ webhookId: 'dummy-webhook', type: 'note' }, root))
.rejects.toThrow(WebhookTestService.NoSuchWebhookError);
});
});
});
describe('testSystemWebhook', () => {
test('abuseReport', async () => {
await service.testSystemWebhook({ webhookId: 'dummy-webhook', type: 'abuseReport' });
const calls = queueService.systemWebhookDeliver.mock.calls[0];
expect((calls[0] as any).id).toBe('dummy-webhook');
expect(calls[1]).toBe('abuseReport');
expect((calls[2] as any).id).toBe('dummy-abuse-report1');
expect((calls[2] as any).resolved).toBe(false);
});
test('abuseReportResolved', async () => {
await service.testSystemWebhook({ webhookId: 'dummy-webhook', type: 'abuseReportResolved' });
const calls = queueService.systemWebhookDeliver.mock.calls[0];
expect((calls[0] as any).id).toBe('dummy-webhook');
expect(calls[1]).toBe('abuseReportResolved');
expect((calls[2] as any).id).toBe('dummy-abuse-report1');
expect((calls[2] as any).resolved).toBe(true);
});
test('userCreated', async () => {
await service.testSystemWebhook({ webhookId: 'dummy-webhook', type: 'userCreated' });
const calls = queueService.systemWebhookDeliver.mock.calls[0];
expect((calls[0] as any).id).toBe('dummy-webhook');
expect(calls[1]).toBe('userCreated');
expect((calls[2] as any).id).toBe('dummy-user-1');
});
});
});

View file

@ -24,7 +24,6 @@ import { MiMeta, MiNote, UserProfilesRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { secureRndstr } from '@/misc/secure-rndstr.js';
import { DownloadService } from '@/core/DownloadService.js';
import { MetaService } from '@/core/MetaService.js';
import type { MiRemoteUser } from '@/models/User.js';
import { genAidx } from '@/misc/id/aidx.js';
import { MockResolver } from '../misc/mock-resolver.js';
@ -107,7 +106,14 @@ describe('ActivityPub', () => {
sensitiveWords: [] as string[],
prohibitedWords: [] as string[],
} as MiMeta;
let meta = metaInitial;
const meta = { ...metaInitial };
function updateMeta(newMeta: Partial<MiMeta>): void {
for (const key in meta) {
delete (meta as any)[key];
}
Object.assign(meta, newMeta);
}
beforeAll(async () => {
const app = await Test.createTestingModule({
@ -120,11 +126,8 @@ describe('ActivityPub', () => {
};
},
})
.overrideProvider(MetaService).useValue({
async fetch(): Promise<MiMeta> {
return meta;
},
}).compile();
.overrideProvider(DI.meta).useFactory({ factory: () => meta })
.compile();
await app.init();
app.enableShutdownHooks();
@ -376,7 +379,7 @@ describe('ActivityPub', () => {
});
test('cacheRemoteFiles=false disables caching', async () => {
meta = { ...metaInitial, cacheRemoteFiles: false };
updateMeta({ ...metaInitial, cacheRemoteFiles: false });
const imageObject: IApDocument = {
type: 'Document',
@ -405,7 +408,7 @@ describe('ActivityPub', () => {
});
test('cacheRemoteSensitiveFiles=false only affects sensitive files', async () => {
meta = { ...metaInitial, cacheRemoteSensitiveFiles: false };
updateMeta({ ...metaInitial, cacheRemoteSensitiveFiles: false });
const imageObject: IApDocument = {
type: 'Document',

View file

@ -4,10 +4,10 @@
*/
import { Test, TestingModule } from '@nestjs/testing';
import type { MiUser } from '@/models/User.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { GlobalModule } from '@/GlobalModule.js';
import { CoreModule } from '@/core/CoreModule.js';
import type { MiUser } from '@/models/User.js';
import { secureRndstr } from '@/misc/secure-rndstr.js';
import { genAidx } from '@/misc/id/aidx.js';
import {
@ -49,6 +49,7 @@ 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';
process.env.NODE_ENV = 'test';
@ -169,6 +170,7 @@ describe('UserEntityService', () => {
ApLoggerService,
AccountMoveService,
ReactionService,
ReactionsBufferingService,
NotificationService,
];