summaryrefslogtreecommitdiff
path: root/packages/backend/test/unit/RoleService.ts
diff options
context:
space:
mode:
authorおさむのひと <46447427+samunohito@users.noreply.github.com>2025-11-10 10:31:49 +0900
committerGitHub <noreply@github.com>2025-11-10 10:31:49 +0900
commitca1bf21dcf654577f9831ed89b24740bfeeaf3f1 (patch)
tree5d223d456ca775f43a55ab3c25b747844fe5a380 /packages/backend/test/unit/RoleService.ts
parentuse esnext to avoid type error (diff)
downloadmisskey-ca1bf21dcf654577f9831ed89b24740bfeeaf3f1.tar.gz
misskey-ca1bf21dcf654577f9831ed89b24740bfeeaf3f1.tar.bz2
misskey-ca1bf21dcf654577f9831ed89b24740bfeeaf3f1.zip
chore: RoleServiceのunit-test追加 (#16777)
Diffstat (limited to 'packages/backend/test/unit/RoleService.ts')
-rw-r--r--packages/backend/test/unit/RoleService.ts255
1 files changed, 237 insertions, 18 deletions
diff --git a/packages/backend/test/unit/RoleService.ts b/packages/backend/test/unit/RoleService.ts
index 306836ea43..62789d28a2 100644
--- a/packages/backend/test/unit/RoleService.ts
+++ b/packages/backend/test/unit/RoleService.ts
@@ -6,7 +6,7 @@
process.env.NODE_ENV = 'test';
import { setTimeout } from 'node:timers/promises';
-import { jest } from '@jest/globals';
+import { describe, jest } from '@jest/globals';
import { ModuleMocker } from 'jest-mock';
import { Test } from '@nestjs/testing';
import * as lolex from '@sinonjs/fake-timers';
@@ -168,6 +168,61 @@ describe('RoleService', () => {
await app.close();
});
+ describe('getUserAssigns', () => {
+ test('アサインされたロールを取得できる', async () => {
+ const user = await createUser();
+ const role1 = await createRole({ name: 'a' });
+ const role2 = await createRole({ name: 'b' });
+
+ await roleService.assign(user.id, role1.id);
+ await roleService.assign(user.id, role2.id);
+
+ const assigns = await roleService.getUserAssigns(user.id);
+ expect(assigns).toHaveLength(2);
+ expect(assigns.some(a => a.roleId === role1.id)).toBe(true);
+ expect(assigns.some(a => a.roleId === role2.id)).toBe(true);
+ });
+
+ test('アサインされたロールの有効/期限切れパターンを取得できる', async () => {
+ const user = await createUser();
+ const roleNoExpiry = await createRole({ name: 'no-expires' });
+ const roleNotExpired = await createRole({ name: 'not-expired' });
+ const roleExpired = await createRole({ name: 'expired' });
+
+ // expiresAtなし
+ await roleService.assign(user.id, roleNoExpiry.id);
+
+ // expiresAtあり(期限切れでない)
+ const future = new Date(Date.now() + 1000 * 60 * 60); // +1 hour
+ await roleService.assign(user.id, roleNotExpired.id, future);
+
+ // expiresAtあり(期限切れ)
+ await assignRole({ userId: user.id, roleId: roleExpired.id, expiresAt: new Date(Date.now() - 1000) });
+
+ const assigns = await roleService.getUserAssigns(user.id);
+ expect(assigns.some(a => a.roleId === roleNoExpiry.id)).toBe(true);
+ expect(assigns.some(a => a.roleId === roleNotExpired.id)).toBe(true);
+ expect(assigns.some(a => a.roleId === roleExpired.id)).toBe(false);
+ });
+ });
+
+ describe('getUserRoles', () => {
+ test('アサインされたロールとコンディショナルロールの両方が取得できる', async () => {
+ const user = await createUser();
+ const manualRole = await createRole({ name: 'manual role' });
+ const conditionalRole = await createConditionalRole({
+ id: aidx(),
+ type: 'isBot',
+ });
+ await roleService.assign(user.id, manualRole.id);
+ await roleService.assign(user.id, conditionalRole.id);
+
+ const roles = await roleService.getUserRoles(user.id);
+ expect(roles.some(r => r.id === manualRole.id)).toBe(true);
+ expect(roles.some(r => r.id === conditionalRole.id)).toBe(true);
+ });
+ });
+
describe('getUserPolicies', () => {
test('instance default policies', async () => {
const user = await createUser();
@@ -280,6 +335,112 @@ describe('RoleService', () => {
const resultAfter25hAgain = await roleService.getUserPolicies(user.id);
expect(resultAfter25hAgain.canManageCustomEmojis).toBe(true);
});
+
+ test('role with no policy set', async () => {
+ const user = await createUser();
+ const roleWithPolicy = await createRole({
+ name: 'roleWithPolicy',
+ policies: {
+ pinLimit: {
+ useDefault: false,
+ priority: 0,
+ value: 10,
+ },
+ },
+ });
+ const roleWithoutPolicy = await createRole({
+ name: 'roleWithoutPolicy',
+ policies: {}, // ポリシーが空
+ });
+ await roleService.assign(user.id, roleWithPolicy.id);
+ await roleService.assign(user.id, roleWithoutPolicy.id);
+ meta.policies = {
+ pinLimit: 5,
+ };
+
+ const result = await roleService.getUserPolicies(user.id);
+
+ // roleWithoutPolicy は default 値 (5) を使い、roleWithPolicy の 10 と比較して大きい方が採用される
+ expect(result.pinLimit).toBe(10);
+ });
+ });
+
+ describe('getUserBadgeRoles', () => {
+ test('手動アサイン済みのバッジロールのみが返る', async () => {
+ const user = await createUser();
+ const badgeRole = await createRole({ name: 'badge', asBadge: true });
+ const normalRole = await createRole({ name: 'normal', asBadge: false });
+
+ await roleService.assign(user.id, badgeRole.id);
+ await roleService.assign(user.id, normalRole.id);
+
+ const roles = await roleService.getUserBadgeRoles(user.id);
+ expect(roles.some(r => r.id === badgeRole.id)).toBe(true);
+ expect(roles.some(r => r.id === normalRole.id)).toBe(false);
+ });
+
+ test('コンディショナルなバッジロールが条件一致で返る', async () => {
+ const user = await createUser({ isBot: true });
+ const condBadgeRole = await createConditionalRole({
+ id: aidx(),
+ type: 'isBot',
+ }, { asBadge: true, name: 'cond-badge' });
+ const condNonBadgeRole = await createConditionalRole({
+ id: aidx(),
+ type: 'isBot',
+ }, { asBadge: false, name: 'cond-non-badge' });
+
+ const roles = await roleService.getUserBadgeRoles(user.id);
+ expect(roles.some(r => r.id === condBadgeRole.id)).toBe(true);
+ expect(roles.some(r => r.id === condNonBadgeRole.id)).toBe(false);
+ });
+
+ test('roleAssignedTo 条件のバッジロール: アサイン有無で変化する', async () => {
+ const [user1, user2] = await Promise.all([createUser(), createUser()]);
+ const manualRole = await createRole({ name: 'manual' });
+ const condBadgeRole = await createConditionalRole({
+ id: aidx(),
+ type: 'roleAssignedTo',
+ roleId: manualRole.id,
+ }, { asBadge: true, name: 'assigned-badge' });
+
+ await roleService.assign(user2.id, manualRole.id);
+
+ const [roles1, roles2] = await Promise.all([
+ roleService.getUserBadgeRoles(user1.id),
+ roleService.getUserBadgeRoles(user2.id),
+ ]);
+ expect(roles1.some(r => r.id === condBadgeRole.id)).toBe(false);
+ expect(roles2.some(r => r.id === condBadgeRole.id)).toBe(true);
+ });
+
+ test('期限切れのバッジロールは除外される', async () => {
+ const user = await createUser();
+ const roleNoExpiry = await createRole({ name: 'no-exp', asBadge: true });
+ const roleNotExpired = await createRole({ name: 'not-expired', asBadge: true });
+ const roleExpired = await createRole({ name: 'expired', asBadge: true });
+
+ // expiresAt なし
+ await roleService.assign(user.id, roleNoExpiry.id);
+
+ // expiresAt あり(期限切れでない)
+ const future = new Date(Date.now() + 1000 * 60 * 60); // +1 hour
+ await roleService.assign(user.id, roleNotExpired.id, future);
+
+ // expiresAt あり(期限切れ)
+ await assignRole({ userId: user.id, roleId: roleExpired.id, expiresAt: new Date(Date.now() - 1000) });
+
+ const rolesBefore = await roleService.getUserBadgeRoles(user.id);
+ expect(rolesBefore.some(r => r.id === roleNoExpiry.id)).toBe(true);
+ expect(rolesBefore.some(r => r.id === roleNotExpired.id)).toBe(true);
+ expect(rolesBefore.some(r => r.id === roleExpired.id)).toBe(false);
+
+ // 時間経過で roleNotExpired を失効させる
+ clock.tick('02:00:00');
+ const rolesAfter = await roleService.getUserBadgeRoles(user.id);
+ expect(rolesAfter.some(r => r.id === roleNoExpiry.id)).toBe(true);
+ expect(rolesAfter.some(r => r.id === roleNotExpired.id)).toBe(false);
+ });
});
describe('getModeratorIds', () => {
@@ -413,9 +574,9 @@ describe('RoleService', () => {
expect(result).toEqual([modeUser1.id, modeUser2.id, rootUser.id]);
});
- test('root has moderator role', async () => {
- const [adminUser1, modeUser1, normalUser1, rootUser] = await Promise.all([
- createUser(), createUser(), createUser(), createRoot(),
+ test('includeAdmins = false, includeRoot = true, excludeExpire = true', async () => {
+ const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2, rootUser] = await Promise.all([
+ createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createRoot(),
]);
const role1 = await createRole({ name: 'admin', isAdministrator: true });
@@ -424,9 +585,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: modeUser1.id, roleId: role2.id }),
- assignRole({ userId: rootUser.id, roleId: role2.id }),
+ assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }),
assignRole({ userId: normalUser1.id, roleId: role3.id }),
+ assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }),
]);
const result = await roleService.getModeratorIds({
@@ -434,12 +597,12 @@ describe('RoleService', () => {
includeRoot: true,
excludeExpire: false,
});
- expect(result).toEqual([modeUser1.id, rootUser.id]);
+ expect(result).toEqual([modeUser1.id, modeUser2.id, rootUser.id]);
});
- test('root has administrator role', async () => {
- const [adminUser1, modeUser1, normalUser1, rootUser] = await Promise.all([
- createUser(), createUser(), createUser(), createRoot(),
+ test('includeAdmins = true, includeRoot = true, excludeExpire = false', async () => {
+ const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2, rootUser] = await Promise.all([
+ createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createRoot(),
]);
const role1 = await createRole({ name: 'admin', isAdministrator: true });
@@ -448,9 +611,11 @@ describe('RoleService', () => {
await Promise.all([
assignRole({ userId: adminUser1.id, roleId: role1.id }),
- assignRole({ userId: rootUser.id, roleId: role1.id }),
+ assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }),
assignRole({ userId: modeUser1.id, roleId: role2.id }),
+ assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }),
assignRole({ userId: normalUser1.id, roleId: role3.id }),
+ assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }),
]);
const result = await roleService.getModeratorIds({
@@ -458,12 +623,12 @@ describe('RoleService', () => {
includeRoot: true,
excludeExpire: false,
});
- expect(result).toEqual([adminUser1.id, modeUser1.id, rootUser.id]);
+ expect(result).toEqual([adminUser1.id, adminUser2.id, modeUser1.id, modeUser2.id, rootUser.id]);
});
- test('root has moderator role(expire)', async () => {
- const [adminUser1, modeUser1, normalUser1, rootUser] = await Promise.all([
- createUser(), createUser(), createUser(), createRoot(),
+ test('includeAdmins = true, includeRoot = true, excludeExpire = true', async () => {
+ const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2, rootUser] = await Promise.all([
+ createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createRoot(),
]);
const role1 = await createRole({ name: 'admin', isAdministrator: true });
@@ -472,17 +637,71 @@ 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: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }),
+ assignRole({ userId: modeUser1.id, roleId: role2.id }),
+ assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }),
assignRole({ userId: normalUser1.id, roleId: role3.id }),
+ assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }),
]);
const result = await roleService.getModeratorIds({
- includeAdmins: false,
+ includeAdmins: true,
includeRoot: true,
excludeExpire: true,
});
- expect(result).toEqual([rootUser.id]);
+ expect(result).toEqual([adminUser1.id, modeUser1.id, rootUser.id]);
+ });
+ });
+
+ describe('getAdministratorIds', () => {
+ test('should return only user IDs with administrator roles', async () => {
+ const adminUser1 = await createUser();
+ const adminUser2 = await createUser();
+ const normalUser = await createUser();
+ const moderatorUser = await createUser();
+
+ const adminRole = await createRole({ name: 'admin', isAdministrator: true, isModerator: false });
+ const moderatorRole = await createRole({ name: 'moderator', isModerator: true, isAdministrator: false });
+ const normalRole = await createRole({ name: 'normal', isAdministrator: false, isModerator: false });
+
+ await roleService.assign(adminUser1.id, adminRole.id);
+ await roleService.assign(adminUser2.id, adminRole.id);
+ await roleService.assign(moderatorUser.id, moderatorRole.id);
+ await roleService.assign(normalUser.id, normalRole.id);
+
+ const adminIds = await roleService.getAdministratorIds();
+
+ // sort for deterministic order
+ adminIds.sort();
+ const expectedIds = [adminUser1.id, adminUser2.id].sort();
+
+ expect(adminIds).toEqual(expectedIds);
+ });
+
+ test('should return an empty array if no users have administrator roles', async () => {
+ const normalUser = await createUser();
+ const normalRole = await createRole({ name: 'normal', isAdministrator: false });
+ await roleService.assign(normalUser.id, normalRole.id);
+
+ const adminIds = await roleService.getAdministratorIds();
+
+ expect(adminIds).toHaveLength(0);
+ });
+
+ test('should return an empty array if there are no administrator roles defined', async () => {
+ await createUser(); // create user to ensure not empty db
+ const adminIds = await roleService.getAdministratorIds();
+ expect(adminIds).toHaveLength(0);
+ });
+
+ // TODO: rootユーザーは現在実装に含まれていないため、テストもそれに倣う
+ test('should not include the root user', async () => {
+ const rootUser = await createUser();
+ meta.rootUserId = rootUser.id;
+
+ const adminIds = await roleService.getAdministratorIds();
+
+ expect(adminIds).not.toContain(rootUser.id);
});
});