OMDSCloud/dictation_server/src/features/files/files.service.spec.ts
saito.k 35e2d626a0 Merged PR 893: API修正(upload-finished)
## 概要
[Task4033: API修正(upload-finished)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/4033)

- JobNumberテーブルから取得したJOBNUMBERを使用してタスクを作成する。
- テスト追加

## レビューポイント
- テストケースは足りているか
- JOBNUMBERの採番ロジックに誤りはないか

## クエリの変更
- Repositoryを変更し、クエリが変更された場合は変更内容を確認する
-  JobNumberテーブルからの取得と更新クエリを追加した
  - 既存のクエリを変更はしていない

## 動作確認状況
- ローカルで確認
- 行った修正がデグレを発生させていないことを確認できるか
  - 具体的にどのような確認をしたか
    - テストケースを修正し、既存テストがすべて通ることを確認

## 補足
- 相談、参考資料などがあれば
2024-05-13 05:04:16 +00:00

3710 lines
116 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { HttpException, HttpStatus } from '@nestjs/common';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
import { makeBlobstorageServiceMockValue } from './test/files.service.mock';
import { DataSource } from 'typeorm';
import {
createJobNumber,
createLicense,
createTask,
createUserGroupAndMember,
getTaskFromJobNumber,
makeTestingModuleWithBlobAndNotification,
updateTaskStatusAndIsJobNumberEnabled,
} from './test/utility';
import { FilesService } from './files.service';
import { makeContext } from '../../common/log';
import {
getJobNumber,
getTasks,
makeHierarchicalAccounts,
makeTestAccount,
makeTestSimpleAccount,
makeTestUser,
} from '../../common/test/utility';
import { makeTestingModule } from '../../common/test/modules';
import {
overrideAdB2cService,
overrideBlobstorageService,
} from '../../common/test/overrides';
import {
createTemplateFile,
getTemplateFiles,
} from '../templates/test/utility';
import { TemplateFilesRepositoryService } from '../../repositories/template_files/template_files.repository.service';
import { makeDefaultNotificationhubServiceMockValue } from '../tasks/test/tasks.service.mock';
import {
createWorkflow,
createWorkflowTypist,
} from '../workflows/test/utility';
import { createWorktype } from '../accounts/test/utility';
import { TasksRepositoryService } from '../../repositories/tasks/tasks.repository.service';
import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service';
import {
createCheckoutPermissions,
getAudioFile,
getCheckoutPermissions,
} from '../tasks/test/utility';
import { DateWithZeroTime } from '../licenses/types/types';
import {
LICENSE_ALLOCATED_STATUS,
LICENSE_TYPE,
TASK_STATUS,
USER_ROLES,
} from '../../constants';
import { truncateAllTable } from '../../common/test/init';
import { TestLogger } from '../../common/test/logger';
import { TasksService } from '../tasks/tasks.service';
describe('publishUploadSas', () => {
let source: DataSource | null = null;
beforeAll(async () => {
if (source == null) {
source = await (async () => {
const s = new DataSource({
type: 'mysql',
host: 'test_mysql_db',
port: 3306,
username: 'user',
password: 'password',
database: 'odms',
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
synchronize: false, // trueにすると自動的にmigrationが行われるため注意
logger: new TestLogger('none'),
logging: true,
});
return await s.initialize();
})();
}
});
beforeEach(async () => {
if (source) {
await truncateAllTable(source);
}
});
afterAll(async () => {
await source?.destroy();
source = null;
});
it('音声アップロードSASトークンが乗っているURLを取得できる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { account: account } = await makeTestAccount(source, { tier: 5 });
const { external_id: externalId, id: userId } = await makeTestUser(source, {
account_id: account.id,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
// 本日の日付を作成
let today = new Date();
today.setDate(today.getDate());
today = new DateWithZeroTime(today);
// 有効期限内のライセンスを作成して紐づける
await createLicense(
source,
1,
today,
account.id,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.ALLOCATED,
userId,
null,
null,
null,
);
const context = makeContext(externalId, 'requestId');
const baseUrl = `https://saodmsusdev.blob.core.windows.net/account-${account.id}/${userId}`;
//SASトークンを返却する
overrideBlobstorageService(service, {
containerExists: async () => true,
publishUploadSas: async () => `${baseUrl}?sas-token`,
});
const url = await service.publishUploadSas(context, externalId);
expect(url).toBe(`${baseUrl}?sas-token`);
});
it('blobストレージにコンテナが存在しない場合はエラーとなる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第四階層のアカウント作成
const { admin } = await makeTestAccount(source, { tier: 4 });
const context = makeContext(admin.external_id, 'requestId');
//Blobコンテナ存在チェックに失敗するようにする
overrideBlobstorageService(service, {
containerExists: async () => false,
publishUploadSas: async () => '',
});
try {
await service.publishUploadSas(context, admin.external_id);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
} else {
fail();
}
}
});
it('SASトークンの取得に失敗した場合はエラーとなる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第四階層のアカウント作成
const { admin } = await makeTestAccount(source, { tier: 4 });
const context = makeContext(admin.external_id, 'requestId');
//BlobのSASトークン生成に失敗するようにする
overrideBlobstorageService(service, {
containerExists: async () => true,
publishUploadSas: async () => {
throw new Error('blob failed');
},
});
try {
await service.publishUploadSas(context, admin.external_id);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
} else {
fail();
}
}
});
it('アカウントがロックされている場合、エラーとなる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { admin } = await makeTestAccount(source, { tier: 5, locked: true });
const context = makeContext(admin.external_id, 'requestId');
try {
await service.publishUploadSas(context, admin.external_id);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E010504'));
} else {
fail();
}
}
});
it('アップロード時にユーザーにライセンスが未割当の場合エラーとなる(第五階層限定)', async () => {
if (!source) fail();
// 第五階層のアカウントまで作成し、そのアカウントに紐づくユーザーを作成する(ライセンスは作成しない)
const { tier4Accounts: tier4Accounts } = await makeHierarchicalAccounts(
source,
);
const tier5Accounts = await makeTestAccount(source, {
parent_account_id: tier4Accounts[0].account.id,
tier: 5,
});
const { external_id: externalId, id: userId } = await makeTestUser(source, {
account_id: tier5Accounts.account.id,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
const blobParam = makeBlobstorageServiceMockValue();
blobParam.publishUploadSas = `${url}?sas-token`;
blobParam.fileExists = false;
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
await expect(
service.publishUploadSas(
makeContext('trackingId', 'requestId'),
externalId,
),
).rejects.toEqual(
new HttpException(makeErrorResponse('E010812'), HttpStatus.BAD_REQUEST),
);
});
});
describe('タスク作成から自動ルーティング(DB使用)', () => {
let source: DataSource | null = null;
beforeAll(async () => {
if (source == null) {
source = await (async () => {
const s = new DataSource({
type: 'mysql',
host: 'test_mysql_db',
port: 3306,
username: 'user',
password: 'password',
database: 'odms',
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
synchronize: false, // trueにすると自動的にmigrationが行われるため注意
logger: new TestLogger('none'),
logging: true,
});
return await s.initialize();
})();
}
});
beforeEach(async () => {
if (source) {
await truncateAllTable(source);
}
});
afterAll(async () => {
await source?.destroy();
source = null;
});
it('タスク作成時に、自動ルーティングを行うことができるAPIの引数として渡されたAuthorIDとworkType', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const {
external_id: authorExternalId,
id: authorUserId,
author_id: authorAuthorId,
} = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const { id: typistUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
author_id: undefined,
});
// ワークタイプを作成
const { id: worktypeId, custom_worktype_id } = await createWorktype(
source,
accountId,
'worktypeId',
);
// テンプレートファイルを作成
const { id: templateFileId } = await createTemplateFile(
source,
accountId,
'templateFile',
'http://blob/url/templateFile.zip',
);
// ワークフローを作成
const { id: workflowId } = await createWorkflow(
source,
accountId,
authorUserId,
worktypeId,
templateFileId,
);
// ワークフロータイピストを作成
await createWorkflowTypist(source, workflowId, typistUserId);
// 初期値のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000000');
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const notificationHubService = module.get<NotificationhubService>(
NotificationhubService,
);
const result = await service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId,
'http://blob/url/file.zip',
authorAuthorId ?? '',
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
custom_worktype_id,
optionItemList,
false,
);
expect(result.jobNumber).toEqual('00000001');
// 通知処理が想定通りの引数で呼ばれているか確認
expect(notificationHubService.notify).toHaveBeenCalledWith(
makeContext('trackingId', 'requestId'),
[`user_${typistUserId}`],
{
authorId: 'AUTHOR_ID',
filename: 'file',
priority: 'High',
uploadedAt: '2023-05-26T11:22:33.444',
},
);
// 作成したタスクを取得
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
// タスクのチェックアウト権限を取得
const resultCheckoutPermission = await getCheckoutPermissions(
source,
resultTask?.id ?? 0,
);
// タスクのテンプレートファイルIDを確認
expect(resultTask?.template_file_id).toEqual(templateFileId);
// タスクのチェックアウト権限が想定通りワークフローで設定されているのユーザーIDで作成されているか確認
expect(resultCheckoutPermission.length).toEqual(1);
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
});
it('別のタスクが既に存在する場合、タスク作成時に、自動ルーティングを行うことができるAPIの引数として渡されたAuthorIDとworkType', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const {
external_id: authorExternalId,
id: authorUserId,
author_id: authorAuthorId,
} = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const { id: typistUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
author_id: undefined,
});
//タスクを作成
await createTask(
source,
accountId,
'http://blob/url/file.zip',
'file.zip',
'Uploaded',
typistUserId,
authorAuthorId ?? '',
);
// ワークタイプを作成
const { id: worktypeId, custom_worktype_id } = await createWorktype(
source,
accountId,
'worktypeId',
);
// ワークフローを作成
const { id: workflowId } = await createWorkflow(
source,
accountId,
authorUserId,
worktypeId,
);
// ワークフロータイピストを作成
await createWorkflowTypist(source, workflowId, typistUserId);
// 最新のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000001');
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const notificationHubService = module.get<NotificationhubService>(
NotificationhubService,
);
const result = await service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId,
'http://blob/url/file.zip',
authorAuthorId ?? '',
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
custom_worktype_id,
optionItemList,
false,
);
expect(result.jobNumber).toEqual('00000002');
// 通知処理が想定通りの引数で呼ばれているか確認
expect(notificationHubService.notify).toHaveBeenCalledWith(
makeContext('trackingId', 'requestId'),
[`user_${typistUserId}`],
{
authorId: 'AUTHOR_ID',
filename: 'file',
priority: 'High',
uploadedAt: '2023-05-26T11:22:33.444',
},
);
// 作成したタスクを取得
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
// タスクのチェックアウト権限を取得
const resultCheckoutPermission = await getCheckoutPermissions(
source,
resultTask?.id ?? 0,
);
// タスクのテンプレートファイルIDを確認
expect(resultTask?.template_file_id).toBeNull();
// タスクのチェックアウト権限が想定通りワークフローで設定されているのユーザーIDで作成されているか確認
expect(resultCheckoutPermission.length).toEqual(1);
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
});
it('タスク作成時に、自動ルーティングを行うことができるAPI実行者のAuthorIDとworkType', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
// 音声ファイルの録音者のユーザー
const { author_id: authorAuthorId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
// ルーティング先のタイピストのユーザー
const { id: typistUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
author_id: undefined,
});
// API実行者のユーザー
const { external_id: myExternalId, id: myUserId } = await makeTestUser(
source,
{
account_id: accountId,
external_id: 'my-author-user-external-id',
role: 'author',
author_id: 'MY_AUTHOR_ID',
},
);
// ワークタイプを作成
const { id: worktypeId, custom_worktype_id } = await createWorktype(
source,
accountId,
'worktypeId',
);
// テンプレートファイルを作成
const { id: templateFileId } = await createTemplateFile(
source,
accountId,
'templateFile',
'http://blob/url/templateFile.zip',
);
// ワークフローを作成
const { id: workflowId } = await createWorkflow(
source,
accountId,
myUserId, // API実行者のユーザーIDを設定
worktypeId,
templateFileId,
);
// ユーザーグループを作成
const { userGroupId } = await createUserGroupAndMember(
source,
accountId,
'userGroupName',
typistUserId, // ルーティング先のタイピストのユーザーIDを設定
);
// ワークフロータイピストを作成
await createWorkflowTypist(
source,
workflowId,
undefined,
userGroupId, // ルーティング先のユーザーグループIDを設定
);
// 初期値のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000000');
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const notificationHubService = module.get<NotificationhubService>(
NotificationhubService,
);
const result = await service.uploadFinished(
makeContext('trackingId', 'requestId'),
myExternalId, // API実行者のユーザーIDを設定
'http://blob/url/file.zip',
authorAuthorId ?? '', // 音声ファイルの情報には、録音者のAuthorIDが入る
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
custom_worktype_id,
optionItemList,
false,
);
expect(result.jobNumber).toEqual('00000001');
// 通知処理が想定通りの引数で呼ばれているか確認
expect(notificationHubService.notify).toHaveBeenCalledWith(
makeContext('trackingId', 'requestId'),
[`user_${typistUserId}`],
{
authorId: 'AUTHOR_ID',
filename: 'file',
priority: 'High',
uploadedAt: '2023-05-26T11:22:33.444',
},
);
// 作成したタスクを取得
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
// タスクのチェックアウト権限を取得
const resultCheckoutPermission = await getCheckoutPermissions(
source,
resultTask?.id ?? 0,
);
// タスクのテンプレートファイルIDを確認
expect(resultTask?.template_file_id).toEqual(templateFileId);
// タスクのチェックアウト権限が想定通りワークフローで設定されているのユーザーIDで作成されているか確認
expect(resultCheckoutPermission.length).toEqual(1);
expect(resultCheckoutPermission[0].user_group_id).toEqual(userGroupId);
});
it('タスク作成時に、音声ファイルメタ情報のAuthorIDに存在しないものが入っていても自動ルーティングを行うことができるAPI実行者のAuthorIDとworkType', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
// 音声ファイルの録音者のユーザー
await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
// ルーティング先のタイピストのユーザー
const { id: typistUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
author_id: undefined,
});
// API実行者のユーザー
const { external_id: myExternalId, id: myUserId } = await makeTestUser(
source,
{
account_id: accountId,
external_id: 'my-author-user-external-id',
role: 'author',
author_id: 'MY_AUTHOR_ID',
},
);
// ワークタイプを作成
const { id: worktypeId, custom_worktype_id } = await createWorktype(
source,
accountId,
'worktypeId',
);
// テンプレートファイルを作成
const { id: templateFileId } = await createTemplateFile(
source,
accountId,
'templateFile',
'http://blob/url/templateFile.zip',
);
// ワークフローを作成
const { id: workflowId } = await createWorkflow(
source,
accountId,
myUserId, // API実行者のユーザーIDを設定
worktypeId,
templateFileId,
);
// ユーザーグループを作成
const { userGroupId } = await createUserGroupAndMember(
source,
accountId,
'userGroupName',
typistUserId, // ルーティング先のタイピストのユーザーIDを設定
);
// ワークフロータイピストを作成
await createWorkflowTypist(
source,
workflowId,
undefined,
userGroupId, // ルーティング先のユーザーグループIDを設定
);
// 初期値のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000000');
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const notificationHubService = module.get<NotificationhubService>(
NotificationhubService,
);
const result = await service.uploadFinished(
makeContext('trackingId', 'requestId'),
myExternalId, // API実行者のユーザーIDを設定
'http://blob/url/file.zip',
'XXXXXXXXXX', // 音声ファイルの情報には、録音者のAuthorIDが入る
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
custom_worktype_id,
optionItemList,
false,
);
expect(result.jobNumber).toEqual('00000001');
// 通知処理が想定通りの引数で呼ばれているか確認
expect(notificationHubService.notify).toHaveBeenCalledWith(
makeContext('trackingId', 'requestId'),
[`user_${typistUserId}`],
{
authorId: 'XXXXXXXXXX',
filename: 'file',
priority: 'High',
uploadedAt: '2023-05-26T11:22:33.444',
},
);
// 作成したタスクを取得
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
// タスクのチェックアウト権限を取得
const resultCheckoutPermission = await getCheckoutPermissions(
source,
resultTask?.id ?? 0,
);
// タスクのテンプレートファイルIDを確認
expect(resultTask?.template_file_id).toEqual(templateFileId);
// タスクのチェックアウト権限が想定通りワークフローで設定されているのユーザーIDで作成されているか確認
expect(resultCheckoutPermission.length).toEqual(1);
expect(resultCheckoutPermission[0].user_group_id).toEqual(userGroupId);
});
it('ワークフローが見つからない場合、タスク作成時に、自動ルーティングを行うことができない', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
// 音声ファイルの録音者のユーザー
const { external_id: authorExternalId, author_id: authorAuthorId } =
await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
// 初期値のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000000');
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const result = await service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId, // API実行者のユーザーIDを設定
'http://blob/url/file.zip',
authorAuthorId ?? '', // 音声ファイルの情報には、録音者のAuthorIDが入る
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
'worktypeId',
optionItemList,
false,
);
expect(result.jobNumber).toEqual('00000001');
// タスクを取得
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
// タスクのチェックアウト権限を取得
const resultCheckoutPermission = await getCheckoutPermissions(
source,
resultTask?.id ?? 0,
);
// タスクがあることを確認
expect(resultTask).not.toBeNull();
// 自動ルーティングが行われていないことを確認
expect(resultCheckoutPermission.length).toEqual(0);
});
it('第五階層アカウントのストレージ使用量が閾値と同値の場合、メール送信が行われない', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
// アカウントを作成する
const { id: accountId } = (
await makeTestAccount(source, {
tier: 5,
company_name: 'company1',
})
).account;
// 音声ファイルの録音者のユーザー
const { external_id: authorExternalId, author_id: authorAuthorId } =
await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
// ライセンスを作成する。ライセンスが2つのため、5GB * 2 = 10GBの上限値となる。
// 閾値は、10GB * 0.8 = 8GBとなる。
const reusableLicense = 2;
for (let i = 0; i < reusableLicense; i++) {
await createLicense(
source,
i + 1,
new Date(2037, 1, 1, 23, 59, 59),
accountId,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.REUSABLE,
null,
null,
null,
null,
);
}
const fileSize = 2 * 1000 * 1000 * 1000; // 2GB
// 3つの音声ファイルを事前作成uploadFinishedで、合計8GBのストレージ使用量状態を作成
for (let i = 0; i < 3; i++) {
await createTask(
source,
accountId,
'url',
'test.zip',
'InProgress',
undefined,
authorAuthorId ?? '',
undefined,
fileSize,
(i + 1).toString().padStart(8, '0'),
);
}
// 最新のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000003');
const service = module.get<FilesService>(FilesService);
const spy = jest
.spyOn(service['sendGridService'], 'sendMail')
.mockImplementation();
const context = makeContext(`uuidv4`, 'xxx-xxx-xxx-xxx', 'requestId');
await service.uploadFinished(
context,
authorExternalId, // API実行者のユーザーIDを設定
'http://blob/url/file.zip',
authorAuthorId ?? '', // 音声ファイルの情報には、録音者のAuthorIDが入る
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
fileSize,
'01',
'DS2',
'comment',
'worktypeId',
optionItemList,
false,
);
expect(spy).not.toHaveBeenCalled();
});
it('第五階層アカウントのストレージ使用量が閾値+1byteの場合、U-118メール送信が行われる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
// アカウントを作成する
const { id: accountId } = (
await makeTestAccount(source, {
tier: 5,
company_name: 'company1',
})
).account;
// 音声ファイルの録音者のユーザー
const { external_id: authorExternalId, author_id: authorAuthorId } =
await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
// ライセンスを作成する。ライセンスが2つのため、5GB * 2 = 10GBの上限値となる。
// 閾値は、10GB * 0.8 = 8GBとなる。
const reusableLicense = 2;
for (let i = 0; i < reusableLicense; i++) {
await createLicense(
source,
i + 1,
new Date(2037, 1, 1, 23, 59, 59),
accountId,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.REUSABLE,
null,
null,
null,
null,
);
}
const fileSize = 2 * 1000 * 1000 * 1000; // 2GB
// 3つの音声ファイルを事前作成uploadFinishedで、合計8GB+1byteのストレージ使用量状態を作成
for (let i = 0; i < 3; i++) {
await createTask(
source,
accountId,
'url',
'test.zip',
'InProgress',
undefined,
authorAuthorId ?? '',
undefined,
fileSize,
(i + 1).toString().padStart(8, '0'),
);
}
// 最新のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000003');
const service = module.get<FilesService>(FilesService);
// メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。
const spy = jest
.spyOn(service['sendGridService'], 'sendMailWithU118')
.mockImplementation();
overrideAdB2cService(service, {
getUsers: async () => [],
});
const context = makeContext(`uuidv4`, 'xxx-xxx-xxx-xxx', 'requestId');
await service.uploadFinished(
context,
authorExternalId, // API実行者のユーザーIDを設定
'http://blob/url/file.zip',
authorAuthorId ?? '', // 音声ファイルの情報には、録音者のAuthorIDが入る
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
fileSize + 1,
'01',
'DS2',
'comment',
'worktypeId',
optionItemList,
false,
);
expect(spy).toHaveBeenCalledTimes(1);
});
it('第五階層アカウントのストレージ使用量が上限と同値の場合、U-118メール送信が行われる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
// アカウントを作成する
const { id: accountId } = (
await makeTestAccount(source, {
tier: 5,
company_name: 'company1',
})
).account;
// 音声ファイルの録音者のユーザー
const { external_id: authorExternalId, author_id: authorAuthorId } =
await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
// ライセンスを作成する。ライセンスが2つのため、5GB * 2 = 10GBの上限値となる。
const reusableLicense = 2;
for (let i = 0; i < reusableLicense; i++) {
await createLicense(
source,
i + 1,
new Date(2037, 1, 1, 23, 59, 59),
accountId,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.REUSABLE,
null,
null,
null,
null,
);
}
const fileSize = 2 * 1000 * 1000 * 1000; // 2GB
// 4つの音声ファイルを事前作成uploadFinishedで、合計10GBのストレージ使用量状態を作成
for (let i = 0; i < 4; i++) {
await createTask(
source,
accountId,
'url',
'test.zip',
'InProgress',
undefined,
authorAuthorId ?? '',
undefined,
fileSize,
(i + 1).toString().padStart(8, '0'),
);
}
// 最新のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000004');
const service = module.get<FilesService>(FilesService);
// メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。
const spy = jest
.spyOn(service['sendGridService'], 'sendMailWithU118')
.mockImplementation();
overrideAdB2cService(service, {
getUsers: async () => [],
});
const context = makeContext(`uuidv4`, 'xxx-xxx-xxx-xxx', 'requestId');
await service.uploadFinished(
context,
authorExternalId, // API実行者のユーザーIDを設定
'http://blob/url/file.zip',
authorAuthorId ?? '', // 音声ファイルの情報には、録音者のAuthorIDが入る
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
fileSize,
'01',
'DS2',
'comment',
'worktypeId',
optionItemList,
false,
);
expect(spy).toHaveBeenCalledTimes(1);
});
it('第五階層アカウントのストレージ使用量が上限+1byteと同値の場合、U-119メール送信が行われる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
// アカウントを作成する
const { id: accountId } = (
await makeTestAccount(source, {
tier: 5,
company_name: 'company1',
})
).account;
// 第一階層アカウントを作成する
await makeTestAccount(source, {
tier: 1,
});
// 音声ファイルの録音者のユーザー
const { external_id: authorExternalId, author_id: authorAuthorId } =
await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
// ライセンスを作成する。ライセンスが2つのため、5GB * 2 = 10GBの上限値となる。
const reusableLicense = 2;
for (let i = 0; i < reusableLicense; i++) {
await createLicense(
source,
i + 1,
new Date(2037, 1, 1, 23, 59, 59),
accountId,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.REUSABLE,
null,
null,
null,
null,
);
}
const fileSize = 2 * 1000 * 1000 * 1000; // 2GB
// 4つの音声ファイルを事前作成uploadFinishedで、合計10GB+1byteのストレージ使用量状態を作成
for (let i = 0; i < 4; i++) {
await createTask(
source,
accountId,
'url',
'test.zip',
'InProgress',
undefined,
authorAuthorId ?? '',
undefined,
fileSize,
(i + 1).toString().padStart(8, '0'),
);
}
// 最新のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000004');
const service = module.get<FilesService>(FilesService);
// メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。
const spy = jest
.spyOn(service['sendGridService'], 'sendMailWithU119')
.mockImplementation();
overrideAdB2cService(service, {
getUsers: async () => [],
});
const context = makeContext(`uuidv4`, 'xxx-xxx-xxx-xxx', 'requestId');
await service.uploadFinished(
context,
authorExternalId, // API実行者のユーザーIDを設定
'http://blob/url/file.zip',
authorAuthorId ?? '', // 音声ファイルの情報には、録音者のAuthorIDが入る
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
fileSize + 1,
'01',
'DS2',
'comment',
'worktypeId',
optionItemList,
false,
);
expect(spy).toHaveBeenCalledTimes(1);
});
it('日付フォーマットが不正な場合、エラーを返却する', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const { external_id: authorExternalId, author_id: authorAuthorId } =
await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
await expect(
service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId,
'http://blob/url/file.zip',
authorAuthorId ?? '',
'file.zip',
'11:22:33',
'yyyy-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
'workTypeID',
optionItemList,
false,
),
).rejects.toEqual(
new HttpException(makeErrorResponse('E010001'), HttpStatus.BAD_REQUEST),
);
});
it('オプションアイテムが10個ない場合、エラーを返却する', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const { external_id: authorExternalId, author_id: authorAuthorId } =
await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
await expect(
service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId,
'http://blob/url/file.zip',
authorAuthorId ?? '',
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
'workTypeID',
[
{
optionItemLabel: 'label_01',
optionItemValue: 'value_01',
},
],
false,
),
).rejects.toEqual(
new HttpException(makeErrorResponse('E010001'), HttpStatus.BAD_REQUEST),
);
});
it('タスク追加でユーザー情報の取得に失敗した場合、エラーを返却する', async () => {
if (!source) fail();
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
await expect(
service.uploadFinished(
makeContext('trackingId', 'requestId'),
'authorExternalId',
'http://blob/url/file.zip',
'authorAuthorId',
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
'workTypeID',
optionItemList,
false,
),
).rejects.toEqual(
new HttpException(
makeErrorResponse('E009999'),
HttpStatus.INTERNAL_SERVER_ERROR,
),
);
});
it('タスクのDBへの追加に失敗した場合、エラーを返却する', async () => {
if (!source) fail();
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const taskRepoService = module.get<TasksRepositoryService>(
TasksRepositoryService,
);
taskRepoService.create = jest.fn().mockRejectedValue(new Error(''));
const { id: accountId } = await makeTestSimpleAccount(source);
const { external_id: authorExternalId, author_id: authorAuthorId } =
await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
await expect(
service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId,
'http://blob/url/file.zip',
authorAuthorId ?? '',
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
'workTypeID',
optionItemList,
false,
),
).rejects.toEqual(
new HttpException(
makeErrorResponse('E009999'),
HttpStatus.INTERNAL_SERVER_ERROR,
),
);
});
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクのジョブナンバーが有効でない場合)', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const {
external_id: authorExternalId,
id: authorUserId,
author_id: authorAuthorId,
} = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const { id: typistUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
author_id: undefined,
});
// ワークタイプを作成
const { id: worktypeId, custom_worktype_id } = await createWorktype(
source,
accountId,
'worktypeId',
);
// テンプレートファイルを作成
const { id: templateFileId } = await createTemplateFile(
source,
accountId,
'templateFile',
'http://blob/url/templateFile.zip',
);
// ワークフローを作成
const { id: workflowId } = await createWorkflow(
source,
accountId,
authorUserId,
worktypeId,
templateFileId,
);
// ワークフロータイピストを作成
await createWorkflowTypist(source, workflowId, typistUserId);
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
// タスクを10件作成, ジョブナンバーは00000001から00000010まで
for (let i = 1; i <= 10; i++) {
await createTask(
source,
accountId,
`http://blob/url/file_${i}.zip`,
`file_${i}.zip`,
'Uploaded',
typistUserId,
authorAuthorId ?? '',
undefined,
undefined,
i.toString().padStart(8, '0'),
);
}
// 最新のジョブナンバーでタスクを取得
const latestTask = await getTaskFromJobNumber(source, '00000010');
// 最新のタスクのステータスとis_job_number_enabledを更新
await updateTaskStatusAndIsJobNumberEnabled(
source,
latestTask?.id ?? 0,
'Backup',
false,
);
// 最新のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000010');
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const notificationHubService = module.get<NotificationhubService>(
NotificationhubService,
);
const result = await service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId,
'http://blob/url/file.zip',
authorAuthorId ?? '',
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
custom_worktype_id,
optionItemList,
false,
);
expect(result.jobNumber).toEqual('00000011');
// 通知処理が想定通りの引数で呼ばれているか確認
expect(notificationHubService.notify).toHaveBeenCalledWith(
makeContext('trackingId', 'requestId'),
[`user_${typistUserId}`],
{
authorId: 'AUTHOR_ID',
filename: 'file',
priority: 'High',
uploadedAt: '2023-05-26T11:22:33.444',
},
);
// 作成したタスクを取得
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
// タスクのチェックアウト権限を取得
const resultCheckoutPermission = await getCheckoutPermissions(
source,
resultTask?.id ?? 0,
);
// タスクのテンプレートファイルIDを確認
expect(resultTask?.template_file_id).toEqual(templateFileId);
// タスクのチェックアウト権限が想定通りワークフローで設定されているのユーザーIDで作成されているか確認
expect(resultCheckoutPermission.length).toEqual(1);
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
});
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクのジョブナンバー有効である場合)', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const {
external_id: authorExternalId,
id: authorUserId,
author_id: authorAuthorId,
} = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const { id: typistUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
author_id: undefined,
});
// ワークタイプを作成
const { id: worktypeId, custom_worktype_id } = await createWorktype(
source,
accountId,
'worktypeId',
);
// テンプレートファイルを作成
const { id: templateFileId } = await createTemplateFile(
source,
accountId,
'templateFile',
'http://blob/url/templateFile.zip',
);
// ワークフローを作成
const { id: workflowId } = await createWorkflow(
source,
accountId,
authorUserId,
worktypeId,
templateFileId,
);
// ワークフロータイピストを作成
await createWorkflowTypist(source, workflowId, typistUserId);
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
// タスクを10件作成, ジョブナンバーは00000001から00000010まで
for (let i = 1; i <= 10; i++) {
await createTask(
source,
accountId,
`http://blob/url/file_${i}.zip`,
`file_${i}.zip`,
'Uploaded',
typistUserId,
authorAuthorId ?? '',
undefined,
undefined,
i.toString().padStart(8, '0'),
);
}
// 最新のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000010');
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const notificationHubService = module.get<NotificationhubService>(
NotificationhubService,
);
const result = await service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId,
'http://blob/url/file.zip',
authorAuthorId ?? '',
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
custom_worktype_id,
optionItemList,
false,
);
expect(result.jobNumber).toEqual('00000011');
// 通知処理が想定通りの引数で呼ばれているか確認
expect(notificationHubService.notify).toHaveBeenCalledWith(
makeContext('trackingId', 'requestId'),
[`user_${typistUserId}`],
{
authorId: 'AUTHOR_ID',
filename: 'file',
priority: 'High',
uploadedAt: '2023-05-26T11:22:33.444',
},
);
// 作成したタスクを取得
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
// タスクのチェックアウト権限を取得
const resultCheckoutPermission = await getCheckoutPermissions(
source,
resultTask?.id ?? 0,
);
// タスクのテンプレートファイルIDを確認
expect(resultTask?.template_file_id).toEqual(templateFileId);
// タスクのチェックアウト権限が想定通りワークフローで設定されているのユーザーIDで作成されているか確認
expect(resultCheckoutPermission.length).toEqual(1);
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
});
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(途中のタスクのジョブナンバーが有効でない場合)', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const {
external_id: authorExternalId,
id: authorUserId,
author_id: authorAuthorId,
} = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const { id: typistUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
author_id: undefined,
});
// ワークタイプを作成
const { id: worktypeId, custom_worktype_id } = await createWorktype(
source,
accountId,
'worktypeId',
);
// テンプレートファイルを作成
const { id: templateFileId } = await createTemplateFile(
source,
accountId,
'templateFile',
'http://blob/url/templateFile.zip',
);
// ワークフローを作成
const { id: workflowId } = await createWorkflow(
source,
accountId,
authorUserId,
worktypeId,
templateFileId,
);
// ワークフロータイピストを作成
await createWorkflowTypist(source, workflowId, typistUserId);
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
// タスクを10件作成, ジョブナンバーは00000001から00000010まで
for (let i = 1; i <= 10; i++) {
await createTask(
source,
accountId,
`http://blob/url/file_${i}.zip`,
`file_${i}.zip`,
'01',
typistUserId,
authorAuthorId ?? '',
undefined,
undefined,
i.toString().padStart(8, '0'),
);
}
// ジョブナンバー00000005のタスクを取得
const middleTask = await getTaskFromJobNumber(source, '00000005');
// ジョブナンバー00000005のタスクのステータスとis_job_number_enabledを更新
await updateTaskStatusAndIsJobNumberEnabled(
source,
middleTask?.id ?? 0,
'Backup',
false,
);
// 最新のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000010');
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const notificationHubService = module.get<NotificationhubService>(
NotificationhubService,
);
const result = await service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId,
'http://blob/url/file.zip',
authorAuthorId ?? '',
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
custom_worktype_id,
optionItemList,
false,
);
expect(result.jobNumber).toEqual('00000011');
// 通知処理が想定通りの引数で呼ばれているか確認
expect(notificationHubService.notify).toHaveBeenCalledWith(
makeContext('trackingId', 'requestId'),
[`user_${typistUserId}`],
{
authorId: 'AUTHOR_ID',
filename: 'file',
priority: 'High',
uploadedAt: '2023-05-26T11:22:33.444',
},
);
// 作成したタスクを取得
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
// タスクのチェックアウト権限を取得
const resultCheckoutPermission = await getCheckoutPermissions(
source,
resultTask?.id ?? 0,
);
// タスクのテンプレートファイルIDを確認
expect(resultTask?.template_file_id).toEqual(templateFileId);
// タスクのチェックアウト権限が想定通りワークフローで設定されているのユーザーIDで作成されているか確認
expect(resultCheckoutPermission.length).toEqual(1);
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
});
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクのジョブナンバーが99999999で有効でない場合)', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const {
external_id: authorExternalId,
id: authorUserId,
author_id: authorAuthorId,
} = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const { id: typistUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
author_id: undefined,
});
// ワークタイプを作成
const { id: worktypeId, custom_worktype_id } = await createWorktype(
source,
accountId,
'worktypeId',
);
// テンプレートファイルを作成
const { id: templateFileId } = await createTemplateFile(
source,
accountId,
'templateFile',
'http://blob/url/templateFile.zip',
);
// ワークフローを作成
const { id: workflowId } = await createWorkflow(
source,
accountId,
authorUserId,
worktypeId,
templateFileId,
);
// ワークフロータイピストを作成
await createWorkflowTypist(source, workflowId, typistUserId);
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
// タスクを10件作成, ジョブナンバーは99999989から99999999まで
for (let i = 99999989; i <= 99999999; i++) {
await createTask(
source,
accountId,
`http://blob/url/file_${i}.zip`,
`file_${i}.zip`,
'01',
typistUserId,
authorAuthorId ?? '',
undefined,
undefined,
i.toString().padStart(8, '0'),
);
}
// 最新ジョブナンバーのタスクを取得
const latestTask = await getTaskFromJobNumber(source, '99999999');
// 最新のタスクのステータスとis_job_number_enabledを更新
await updateTaskStatusAndIsJobNumberEnabled(
source,
latestTask?.id ?? 0,
'Backup',
false,
);
// 最新のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '99999999');
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const notificationHubService = module.get<NotificationhubService>(
NotificationhubService,
);
const result = await service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId,
'http://blob/url/file.zip',
authorAuthorId ?? '',
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
custom_worktype_id,
optionItemList,
false,
);
expect(result.jobNumber).toEqual('00000001');
// 通知処理が想定通りの引数で呼ばれているか確認
expect(notificationHubService.notify).toHaveBeenCalledWith(
makeContext('trackingId', 'requestId'),
[`user_${typistUserId}`],
{
authorId: 'AUTHOR_ID',
filename: 'file',
priority: 'High',
uploadedAt: '2023-05-26T11:22:33.444',
},
);
// 作成したタスクを取得
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
// タスクのチェックアウト権限を取得
const resultCheckoutPermission = await getCheckoutPermissions(
source,
resultTask?.id ?? 0,
);
// タスクのテンプレートファイルIDを確認
expect(resultTask?.template_file_id).toEqual(templateFileId);
// タスクのチェックアウト権限が想定通りワークフローで設定されているのユーザーIDで作成されているか確認
expect(resultCheckoutPermission.length).toEqual(1);
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
});
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクのジョブナンバーが99999999で有効な場合)', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const {
external_id: authorExternalId,
id: authorUserId,
author_id: authorAuthorId,
} = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const { id: typistUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
author_id: undefined,
});
// ワークタイプを作成
const { id: worktypeId, custom_worktype_id } = await createWorktype(
source,
accountId,
'worktypeId',
);
// テンプレートファイルを作成
const { id: templateFileId } = await createTemplateFile(
source,
accountId,
'templateFile',
'http://blob/url/templateFile.zip',
);
// ワークフローを作成
const { id: workflowId } = await createWorkflow(
source,
accountId,
authorUserId,
worktypeId,
templateFileId,
);
// ワークフロータイピストを作成
await createWorkflowTypist(source, workflowId, typistUserId);
// 最新のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '99999999');
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
// タスクを10件作成, ジョブナンバーは99999989から99999999まで
for (let i = 99999989; i <= 99999999; i++) {
await createTask(
source,
accountId,
`http://blob/url/file_${i}.zip`,
`file_${i}.zip`,
'01',
typistUserId,
authorAuthorId ?? '',
undefined,
undefined,
i.toString().padStart(8, '0'),
);
}
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const notificationHubService = module.get<NotificationhubService>(
NotificationhubService,
);
const result = await service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId,
'http://blob/url/file.zip',
authorAuthorId ?? '',
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
custom_worktype_id,
optionItemList,
false,
);
expect(result.jobNumber).toEqual('00000001');
// 通知処理が想定通りの引数で呼ばれているか確認
expect(notificationHubService.notify).toHaveBeenCalledWith(
makeContext('trackingId', 'requestId'),
[`user_${typistUserId}`],
{
authorId: 'AUTHOR_ID',
filename: 'file',
priority: 'High',
uploadedAt: '2023-05-26T11:22:33.444',
},
);
// 作成したタスクを取得
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
// タスクのチェックアウト権限を取得
const resultCheckoutPermission = await getCheckoutPermissions(
source,
resultTask?.id ?? 0,
);
// タスクのテンプレートファイルIDを確認
expect(resultTask?.template_file_id).toEqual(templateFileId);
// タスクのチェックアウト権限が想定通りワークフローで設定されているのユーザーIDで作成されているか確認
expect(resultCheckoutPermission.length).toEqual(1);
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
});
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクが削除されている場合)', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const {
external_id: authorExternalId,
id: authorUserId,
author_id: authorAuthorId,
} = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const { id: typistUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
author_id: undefined,
});
// ワークタイプを作成
const { id: worktypeId, custom_worktype_id } = await createWorktype(
source,
accountId,
'worktypeId',
);
// テンプレートファイルを作成
const { id: templateFileId } = await createTemplateFile(
source,
accountId,
'templateFile',
'http://blob/url/templateFile.zip',
);
// ワークフローを作成
const { id: workflowId } = await createWorkflow(
source,
accountId,
authorUserId,
worktypeId,
templateFileId,
);
// ワークフロータイピストを作成
await createWorkflowTypist(source, workflowId, typistUserId);
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
// タスクを10件作成, ジョブナンバーは00000001から00000010まで
for (let i = 1; i <= 10; i++) {
await createTask(
source,
accountId,
`http://blob/url/file_${i}.zip`,
`file_${i}.zip`,
'Uploaded',
typistUserId,
authorAuthorId ?? '',
undefined,
undefined,
i.toString().padStart(8, '0'),
);
}
// 最新のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000010');
{
// 初期データ確認
const tasks = await getTasks(source, accountId);
expect(tasks.length).toEqual(10);
const jobNumber = await getJobNumber(source, accountId);
expect(jobNumber?.job_number).toEqual('00000010');
}
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const taskService = module.get<TasksService>(TasksService);
const notificationHubService = module.get<NotificationhubService>(
NotificationhubService,
);
// 最新のジョブナンバーのタスクを取得
const latestTask = await getTaskFromJobNumber(source, '00000010');
await taskService.deleteTask(
makeContext('trackingId', 'requestId'),
authorExternalId,
latestTask?.audio_file_id ?? 0, // 最新タスクのaudioFileId
);
{
// タスク削除確認
const tasks = await getTasks(source, accountId);
expect(tasks.length).toEqual(9);
// JobNumberが00000010のタスクが存在しないことを確認
expect(
tasks.find((task) => task.job_number === '00000010'),
).toBeUndefined();
}
const result = await service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId,
'http://blob/url/file.zip',
authorAuthorId ?? '',
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
custom_worktype_id,
optionItemList,
false,
);
expect(result.jobNumber).toEqual('00000011');
// job_numberテーブルが正しく更新されているか確認
const jobNumber = await getJobNumber(source, accountId);
expect(jobNumber?.job_number).toEqual('00000011');
// 通知処理が想定通りの引数で呼ばれているか確認
expect(notificationHubService.notify).toHaveBeenCalledWith(
makeContext('trackingId', 'requestId'),
[`user_${typistUserId}`],
{
authorId: 'AUTHOR_ID',
filename: 'file',
priority: 'High',
uploadedAt: '2023-05-26T11:22:33.444',
},
);
// 作成したタスクを取得
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
// タスクのチェックアウト権限を取得
const resultCheckoutPermission = await getCheckoutPermissions(
source,
resultTask?.id ?? 0,
);
// タスクのテンプレートファイルIDを確認
expect(resultTask?.template_file_id).toEqual(templateFileId);
// タスクのチェックアウト権限が想定通りワークフローで設定されているのユーザーIDで作成されているか確認
expect(resultCheckoutPermission.length).toEqual(1);
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
});
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(途中のタスクが削除されている場合)', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const {
external_id: authorExternalId,
id: authorUserId,
author_id: authorAuthorId,
} = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const { id: typistUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
author_id: undefined,
});
// ワークタイプを作成
const { id: worktypeId, custom_worktype_id } = await createWorktype(
source,
accountId,
'worktypeId',
);
// テンプレートファイルを作成
const { id: templateFileId } = await createTemplateFile(
source,
accountId,
'templateFile',
'http://blob/url/templateFile.zip',
);
// ワークフローを作成
const { id: workflowId } = await createWorkflow(
source,
accountId,
authorUserId,
worktypeId,
templateFileId,
);
// ワークフロータイピストを作成
await createWorkflowTypist(source, workflowId, typistUserId);
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
// タスクを10件作成, ジョブナンバーは00000001から00000010まで
for (let i = 1; i <= 10; i++) {
await createTask(
source,
accountId,
`http://blob/url/file_${i}.zip`,
`file_${i}.zip`,
'Uploaded',
typistUserId,
authorAuthorId ?? '',
undefined,
undefined,
i.toString().padStart(8, '0'),
);
}
// 最新のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '00000010');
{
// 初期データ確認
const tasks = await getTasks(source, accountId);
expect(tasks.length).toEqual(10);
const jobNumber = await getJobNumber(source, accountId);
expect(jobNumber?.job_number).toEqual('00000010');
}
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const taskService = module.get<TasksService>(TasksService);
const notificationHubService = module.get<NotificationhubService>(
NotificationhubService,
);
// 途中のジョブナンバーのタスクを取得
const latestTask = await getTaskFromJobNumber(source, '00000005');
await taskService.deleteTask(
makeContext('trackingId', 'requestId'),
authorExternalId,
latestTask?.audio_file_id ?? 0, // 最新タスクのaudioFileId
);
{
// タスク削除確認
const tasks = await getTasks(source, accountId);
expect(tasks.length).toEqual(9);
// JobNumberが00000005のタスクが存在しないことを確認
expect(
tasks.find((task) => task.job_number === '00000005'),
).toBeUndefined();
}
const result = await service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId,
'http://blob/url/file.zip',
authorAuthorId ?? '',
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
custom_worktype_id,
optionItemList,
false,
);
expect(result.jobNumber).toEqual('00000011');
// job_numberテーブルが正しく更新されているか確認
const jobNumber = await getJobNumber(source, accountId);
expect(jobNumber?.job_number).toEqual('00000011');
// 通知処理が想定通りの引数で呼ばれているか確認
expect(notificationHubService.notify).toHaveBeenCalledWith(
makeContext('trackingId', 'requestId'),
[`user_${typistUserId}`],
{
authorId: 'AUTHOR_ID',
filename: 'file',
priority: 'High',
uploadedAt: '2023-05-26T11:22:33.444',
},
);
// 作成したタスクを取得
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
// タスクのチェックアウト権限を取得
const resultCheckoutPermission = await getCheckoutPermissions(
source,
resultTask?.id ?? 0,
);
// タスクのテンプレートファイルIDを確認
expect(resultTask?.template_file_id).toEqual(templateFileId);
// タスクのチェックアウト権限が想定通りワークフローで設定されているのユーザーIDで作成されているか確認
expect(resultCheckoutPermission.length).toEqual(1);
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
});
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクのジョブナンバーが99999999で削除されている場合)', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const {
external_id: authorExternalId,
id: authorUserId,
author_id: authorAuthorId,
} = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const { id: typistUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
author_id: undefined,
});
// ワークタイプを作成
const { id: worktypeId, custom_worktype_id } = await createWorktype(
source,
accountId,
'worktypeId',
);
// テンプレートファイルを作成
const { id: templateFileId } = await createTemplateFile(
source,
accountId,
'templateFile',
'http://blob/url/templateFile.zip',
);
// ワークフローを作成
const { id: workflowId } = await createWorkflow(
source,
accountId,
authorUserId,
worktypeId,
templateFileId,
);
// ワークフロータイピストを作成
await createWorkflowTypist(source, workflowId, typistUserId);
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
// タスクを10件作成, ジョブナンバーは99999989から99999999まで
for (let i = 99999989; i <= 99999999; i++) {
await createTask(
source,
accountId,
`http://blob/url/file_${i}.zip`,
`file_${i}.zip`,
'Uploaded',
typistUserId,
authorAuthorId ?? '',
undefined,
undefined,
i.toString().padStart(8, '0'),
);
}
// 最新のジョブナンバーでjob_numberテーブルを作成
await createJobNumber(source, accountId, '99999999');
{
// 初期データ確認
const tasks = await getTasks(source, accountId);
expect(tasks.length).toEqual(11);
const jobNumber = await getJobNumber(source, accountId);
expect(jobNumber?.job_number).toEqual('99999999');
}
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const taskService = module.get<TasksService>(TasksService);
const notificationHubService = module.get<NotificationhubService>(
NotificationhubService,
);
// 最新のジョブナンバーのタスクを取得
const latestTask = await getTaskFromJobNumber(source, '99999999');
await taskService.deleteTask(
makeContext('trackingId', 'requestId'),
authorExternalId,
latestTask?.audio_file_id ?? 0, // 最新タスクのaudioFileId
);
{
// タスク削除確認
const tasks = await getTasks(source, accountId);
expect(tasks.length).toEqual(10);
// JobNumberが99999999のタスクが存在しないことを確認
expect(
tasks.find((task) => task.job_number === '99999999'),
).toBeUndefined();
}
const result = await service.uploadFinished(
makeContext('trackingId', 'requestId'),
authorExternalId,
'http://blob/url/file.zip',
authorAuthorId ?? '',
'file.zip',
'11:22:33',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
'2023-05-26T11:22:33.444',
256,
'01',
'DS2',
'comment',
custom_worktype_id,
optionItemList,
false,
);
expect(result.jobNumber).toEqual('00000001');
// job_numberテーブルが正しく更新されているか確認
// 最新タスクのジョブナンバーが99999999の時、新規作成されたタスクのジョブナンバーは00000001になる
const jobNumber = await getJobNumber(source, accountId);
expect(jobNumber?.job_number).toEqual('00000001');
// 通知処理が想定通りの引数で呼ばれているか確認
expect(notificationHubService.notify).toHaveBeenCalledWith(
makeContext('trackingId', 'requestId'),
[`user_${typistUserId}`],
{
authorId: 'AUTHOR_ID',
filename: 'file',
priority: 'High',
uploadedAt: '2023-05-26T11:22:33.444',
},
);
// 作成したタスクを取得
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
// タスクのチェックアウト権限を取得
const resultCheckoutPermission = await getCheckoutPermissions(
source,
resultTask?.id ?? 0,
);
// タスクのテンプレートファイルIDを確認
expect(resultTask?.template_file_id).toEqual(templateFileId);
// タスクのチェックアウト権限が想定通りワークフローで設定されているのユーザーIDで作成されているか確認
expect(resultCheckoutPermission.length).toEqual(1);
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
});
});
describe('音声ファイルダウンロードURL取得', () => {
let source: DataSource | null = null;
beforeAll(async () => {
if (source == null) {
source = await (async () => {
const s = new DataSource({
type: 'mysql',
host: 'test_mysql_db',
port: 3306,
username: 'user',
password: 'password',
database: 'odms',
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
synchronize: false, // trueにすると自動的にmigrationが行われるため注意
logger: new TestLogger('none'),
logging: true,
});
return await s.initialize();
})();
}
});
beforeEach(async () => {
if (source) {
await truncateAllTable(source);
}
});
afterAll(async () => {
await source?.destroy();
source = null;
});
it('ダウンロードSASトークンが乗っているURLを取得できる', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const {
external_id: externalId,
id: userId,
author_id: authorId,
} = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/${userId}`;
const { audioFileId } = await createTask(
source,
accountId,
url,
'test.zip',
'InProgress',
undefined,
authorId ?? '',
);
const blobParam = makeBlobstorageServiceMockValue();
blobParam.publishDownloadSas = `${url}?sas-token`;
blobParam.fileExists = true;
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
expect(
await service.publishAudioFileDownloadSas(
makeContext('trackingId', 'requestId'),
externalId,
audioFileId,
),
).toEqual(`${url}?sas-token`);
});
it('Typistの場合、タスクのステータスが[Inprogress,Pending]以外でエラー', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const { external_id: externalId, id: userId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
});
const { id: authorUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/${authorUserId}`;
const { audioFileId } = await createTask(
source,
accountId,
url,
'test.zip',
'Finished',
userId,
);
const blobParam = makeBlobstorageServiceMockValue();
blobParam.publishDownloadSas = `${url}?sas-token`;
blobParam.fileExists = true;
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
await expect(
service.publishAudioFileDownloadSas(
makeContext('trackingId', 'requestId'),
externalId,
audioFileId,
),
).rejects.toEqual(
new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST),
);
});
it('Typistの場合、自身が担当するタスクでない場合エラー', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const { external_id: externalId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: 'typist',
});
const { id: otherId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'other-typist-user-external-id',
role: 'typist',
});
const { id: authorUserId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/${authorUserId}`;
const { audioFileId } = await createTask(
source,
accountId,
url,
'test.zip',
'InProgress',
otherId,
);
const blobParam = makeBlobstorageServiceMockValue();
blobParam.publishDownloadSas = `${url}?sas-token`;
blobParam.fileExists = true;
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
await expect(
service.publishTemplateFileDownloadSas(
makeContext('tracking', 'requestId'),
externalId,
audioFileId,
),
).rejects.toEqual(
new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST),
);
});
it('Authorの場合、自身が登録したタスクでない場合エラー', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const { external_id: externalId, id: userId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/${userId}`;
const { audioFileId } = await createTask(
source,
accountId,
url,
'test.zip',
'InProgress',
undefined,
'OTHOR_ID',
);
const blobParam = makeBlobstorageServiceMockValue();
blobParam.publishDownloadSas = `${url}?sas-token`;
blobParam.fileExists = true;
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
await expect(
service.publishAudioFileDownloadSas(
makeContext('trackingId', 'requestId'),
externalId,
audioFileId,
),
).rejects.toEqual(
new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST),
);
});
it('Taskが存在しない場合はエラーとなる', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const { external_id: externalId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
await expect(
service.publishAudioFileDownloadSas(
makeContext('trackingId', 'requestId'),
externalId,
1,
),
).rejects.toEqual(
new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST),
);
});
it('blobストレージにファイルが存在しない場合はエラーとなる', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const {
external_id: externalId,
id: userId,
author_id: authorId,
} = await makeTestUser(source, {
account_id: accountId,
external_id: 'author-user-external-id',
role: 'author',
author_id: 'AUTHOR_ID',
});
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/${userId}`;
const { audioFileId } = await createTask(
source,
accountId,
url,
'test.zip',
'InProgress',
undefined,
authorId ?? '',
);
const blobParam = makeBlobstorageServiceMockValue();
blobParam.publishDownloadSas = `${url}?sas-token`;
blobParam.fileExists = false;
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
await expect(
service.publishAudioFileDownloadSas(
makeContext('trackingId', 'requestId'),
externalId,
audioFileId,
),
).rejects.toEqual(
new HttpException(makeErrorResponse('E010701'), HttpStatus.BAD_REQUEST),
);
});
});
describe('テンプレートファイルダウンロードURL取得', () => {
let source: DataSource | null = null;
beforeAll(async () => {
if (source == null) {
source = await (async () => {
const s = new DataSource({
type: 'mysql',
host: 'test_mysql_db',
port: 3306,
username: 'user',
password: 'password',
database: 'odms',
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
synchronize: false, // trueにすると自動的にmigrationが行われるため注意
logger: new TestLogger('none'),
logging: true,
});
return await s.initialize();
})();
}
});
beforeEach(async () => {
if (source) {
await truncateAllTable(source);
}
});
afterAll(async () => {
await source?.destroy();
source = null;
});
it('ダウンロードSASトークンが乗っているURLを取得できる', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const { external_id: externalId, id: userId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: USER_ROLES.TYPIST,
});
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/Templates`;
const { audioFileId } = await createTask(
source,
accountId,
url,
'test.zip',
TASK_STATUS.IN_PROGRESS,
userId,
'AUTHOR_ID',
);
const blobParam = makeBlobstorageServiceMockValue();
blobParam.publishDownloadSas = `${url}?sas-token`;
blobParam.fileExists = true;
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
const resultUrl = await service.publishTemplateFileDownloadSas(
makeContext('tracking', 'requestId'),
externalId,
audioFileId,
);
expect(resultUrl).toBe(`${url}?sas-token`);
});
it('タスクのステータスが[Inprogress,Pending]以外でエラー', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const { external_id: externalId, id: userId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: USER_ROLES.TYPIST,
});
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/Templates`;
const { audioFileId } = await createTask(
source,
accountId,
url,
'test.zip',
TASK_STATUS.FINISHED,
userId,
);
const blobParam = makeBlobstorageServiceMockValue();
blobParam.publishDownloadSas = `${url}?sas-token`;
blobParam.fileExists = true;
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
try {
await service.publishTemplateFileDownloadSas(
makeContext('tracking', 'requestId'),
externalId,
audioFileId,
);
fail();
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E010603'));
} else {
fail();
}
}
});
it('自身が担当するタスクでない場合エラー', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const { external_id: externalId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: USER_ROLES.TYPIST,
});
const { id: otherId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'other-typist-user-external-id',
role: USER_ROLES.TYPIST,
});
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/Templates`;
const { audioFileId } = await createTask(
source,
accountId,
url,
'test.zip',
TASK_STATUS.IN_PROGRESS,
otherId,
);
const blobParam = makeBlobstorageServiceMockValue();
blobParam.publishDownloadSas = `${url}?sas-token`;
blobParam.fileExists = true;
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
try {
await service.publishTemplateFileDownloadSas(
makeContext('tracking', 'requestId'),
externalId,
audioFileId,
);
fail();
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E010603'));
} else {
fail();
}
}
});
it('Taskが存在しない場合はエラーとなる', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const { external_id: externalId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: USER_ROLES.TYPIST,
});
const blobParam = makeBlobstorageServiceMockValue();
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
try {
await service.publishTemplateFileDownloadSas(
makeContext('tracking', 'requestId'),
externalId,
1,
);
fail();
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E010603'));
} else {
fail();
}
}
});
it('blobストレージにファイルが存在しない場合はエラーとなる', async () => {
if (!source) fail();
const { id: accountId } = await makeTestSimpleAccount(source);
const { external_id: externalId, id: userId } = await makeTestUser(source, {
account_id: accountId,
external_id: 'typist-user-external-id',
role: USER_ROLES.TYPIST,
});
const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/Templates`;
const { audioFileId } = await createTask(
source,
accountId,
url,
'test.zip',
TASK_STATUS.IN_PROGRESS,
userId,
'AUTHOR_ID',
);
const blobParam = makeBlobstorageServiceMockValue();
blobParam.publishDownloadSas = `${url}?sas-token`;
blobParam.fileExists = false;
const notificationParam = makeDefaultNotificationhubServiceMockValue();
const module = await makeTestingModuleWithBlobAndNotification(
source,
blobParam,
notificationParam,
);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
try {
await service.publishTemplateFileDownloadSas(
makeContext('tracking', 'requestId'),
externalId,
audioFileId,
);
fail();
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E010701'));
} else {
fail();
}
}
});
});
describe('publishTemplateFileUploadSas', () => {
let source: DataSource | null = null;
beforeAll(async () => {
if (source == null) {
source = await (async () => {
const s = new DataSource({
type: 'mysql',
host: 'test_mysql_db',
port: 3306,
username: 'user',
password: 'password',
database: 'odms',
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
synchronize: false, // trueにすると自動的にmigrationが行われるため注意
logger: new TestLogger('none'),
logging: true,
});
return await s.initialize();
})();
}
});
beforeEach(async () => {
if (source) {
await truncateAllTable(source);
}
});
afterAll(async () => {
await source?.destroy();
source = null;
});
it('テンプレートファイルアップロードSASトークンが乗っているURLを取得できる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const context = makeContext(admin.external_id, 'requestId');
const baseUrl = `https://saodmsusdev.blob.core.windows.net/account-${account.id}/Templates`;
//SASトークンを返却する
overrideBlobstorageService(service, {
containerExists: async () => true,
publishTemplateUploadSas: async () => `${baseUrl}?sas-token`,
});
const url = await service.publishTemplateFileUploadSas(
context,
admin.external_id,
);
expect(url).toBe(`${baseUrl}?sas-token`);
});
it('blobストレージにコンテナが存在しない場合はエラーとなる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { admin } = await makeTestAccount(source, { tier: 5 });
const context = makeContext(admin.external_id, 'requestId');
//Blobコンテナ存在チェックに失敗するようにする
overrideBlobstorageService(service, {
containerExists: async () => false,
publishTemplateUploadSas: async () => '',
});
try {
await service.publishTemplateFileUploadSas(context, admin.external_id);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
} else {
fail();
}
}
});
it('SASトークンの取得に失敗した場合はエラーとなる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { admin } = await makeTestAccount(source, { tier: 5 });
const context = makeContext(admin.external_id, 'requestId');
//BlobのSASトークン生成に失敗するようにする
overrideBlobstorageService(service, {
containerExists: async () => true,
publishTemplateUploadSas: async () => {
throw new Error('blob failed');
},
});
try {
await service.publishTemplateFileUploadSas(context, admin.external_id);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
} else {
fail();
}
}
});
});
describe('templateUploadFinished', () => {
let source: DataSource | null = null;
beforeAll(async () => {
if (source == null) {
source = await (async () => {
const s = new DataSource({
type: 'mysql',
host: 'test_mysql_db',
port: 3306,
username: 'user',
password: 'password',
database: 'odms',
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
synchronize: false, // trueにすると自動的にmigrationが行われるため注意
logger: new TestLogger('none'),
logging: true,
});
return await s.initialize();
})();
}
});
beforeEach(async () => {
if (source) {
await truncateAllTable(source);
}
});
afterAll(async () => {
await source?.destroy();
source = null;
});
it('アップロード完了後のテンプレートファイル情報をDBに保存できる新規追加', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const context = makeContext(admin.external_id, 'requestId');
const fileName = 'test.docs';
const url = `https://blob.url/account-${account.id}/Templates`;
// 事前にDBを確認
{
const templates = await getTemplateFiles(source, account.id);
expect(templates.length).toBe(0);
}
await service.templateUploadFinished(
context,
admin.external_id,
url,
fileName,
);
//実行結果を確認
{
const templates = await getTemplateFiles(source, account.id);
expect(templates.length).toBe(1);
expect(templates[0].file_name).toBe(fileName);
expect(templates[0].url).toBe(url);
}
});
it('アップロード完了後のテンプレートファイル情報をDBに保存できる更新', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const context = makeContext(admin.external_id, 'requestId');
const fileName = 'test.docs';
const url = `https://blob.url/account-${account.id}/Templates`;
await createTemplateFile(source, account.id, fileName, url);
// 事前にDBを確認
{
const templates = await getTemplateFiles(source, account.id);
expect(templates.length).toBe(1);
expect(templates[0].file_name).toBe(fileName);
expect(templates[0].url).toBe(url);
}
const updateUrl = `https://blob.update.url/account-${account.id}/Templates`;
await service.templateUploadFinished(
context,
admin.external_id,
updateUrl,
fileName,
);
//実行結果を確認
{
const templates = await getTemplateFiles(source, account.id);
expect(templates.length).toBe(1);
expect(templates[0].file_name).toBe(fileName);
expect(templates[0].url).toBe(updateUrl);
}
});
it('DBへの保存に失敗した場合はエラーとなる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const context = makeContext(admin.external_id, 'requestId');
const fileName = 'test.docs';
const url = `https://blob.url/account-${account.id}/Templates`;
// 事前にDBを確認
{
const templates = await getTemplateFiles(source, account.id);
expect(templates.length).toBe(0);
}
//DBアクセスに失敗するようにする
const templatesService = module.get<TemplateFilesRepositoryService>(
TemplateFilesRepositoryService,
);
templatesService.upsertTemplateFile = jest
.fn()
.mockRejectedValue('DB failed');
try {
await service.templateUploadFinished(
context,
admin.external_id,
url,
fileName,
);
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
} else {
fail();
}
}
});
});
const optionItemList = [
{
optionItemLabel: 'label_01',
optionItemValue: 'value_01',
},
{
optionItemLabel: 'label_02',
optionItemValue: 'value_02',
},
{
optionItemLabel: 'label_03',
optionItemValue: 'value_03',
},
{
optionItemLabel: 'label_04',
optionItemValue: 'value_04',
},
{
optionItemLabel: 'label_05',
optionItemValue: 'value_05',
},
{
optionItemLabel: 'label_06',
optionItemValue: 'value_06',
},
{
optionItemLabel: 'label_07',
optionItemValue: 'value_07',
},
{
optionItemLabel: 'label_08',
optionItemValue: 'value_08',
},
{
optionItemLabel: 'label_09',
optionItemValue: 'value_09',
},
{
optionItemLabel: 'label_10',
optionItemValue: 'value_10',
},
];
describe('fileRename', () => {
let source: DataSource | null = null;
beforeAll(async () => {
if (source == null) {
source = await (async () => {
const s = new DataSource({
type: 'mysql',
host: 'test_mysql_db',
port: 3306,
username: 'user',
password: 'password',
database: 'odms',
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
synchronize: false, // trueにすると自動的にmigrationが行われるため注意
logger: new TestLogger('none'),
logging: true,
});
return await s.initialize();
})();
}
});
beforeEach(async () => {
if (source) {
await truncateAllTable(source);
}
});
afterAll(async () => {
await source?.destroy();
source = null;
});
it('ファイル名を変更できる(管理者)', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const context = makeContext(admin.external_id, 'requestId');
const oldFileName = 'old.zip';
const task = await createTask(
source,
account.id,
'https://blob.url/account-1',
oldFileName,
TASK_STATUS.UPLOADED,
);
// 事前にDBを確認
{
const audioFile = await getAudioFile(source, task.audioFileId);
expect(audioFile?.file_name).toBe(oldFileName);
expect(audioFile?.raw_file_name).toBe(oldFileName);
}
const newFileName = 'new.zip';
await service.fileRename(
context,
admin.external_id,
task.audioFileId,
newFileName,
);
//実行結果を確認
{
const audioFile = await getAudioFile(source, task.audioFileId);
expect(audioFile?.file_name).toBe(newFileName);
expect(audioFile?.raw_file_name).toBe(oldFileName);
}
});
it('ファイル名を変更できるAuthor', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { account } = await makeTestAccount(source, { tier: 5 });
const { external_id: authorExternalId } = await makeTestUser(source, {
account_id: account.id,
external_id: 'author-user-external-id',
role: USER_ROLES.AUTHOR,
author_id: 'AUTHOR_ID',
});
const context = makeContext(authorExternalId, 'requestId');
const oldFileName = 'old.zip';
const task = await createTask(
source,
account.id,
'https://blob.url/account-1',
oldFileName,
TASK_STATUS.UPLOADED,
undefined,
'AUTHOR_ID',
);
// 事前にDBを確認
{
const audioFile = await getAudioFile(source, task.audioFileId);
expect(audioFile?.file_name).toBe(oldFileName);
expect(audioFile?.raw_file_name).toBe(oldFileName);
}
const newFileName = 'new.zip';
await service.fileRename(
context,
authorExternalId,
task.audioFileId,
newFileName,
);
//実行結果を確認
{
const audioFile = await getAudioFile(source, task.audioFileId);
expect(audioFile?.file_name).toBe(newFileName);
expect(audioFile?.raw_file_name).toBe(oldFileName);
}
});
it('ファイル名を変更できるTypist', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { account } = await makeTestAccount(source, { tier: 5 });
const { external_id: typistExternalId, id: typistId } = await makeTestUser(
source,
{
account_id: account.id,
external_id: 'typist-user-external-id',
role: USER_ROLES.TYPIST,
},
);
const context = makeContext(typistExternalId, 'requestId');
const oldFileName = 'old.zip';
const task = await createTask(
source,
account.id,
'https://blob.url/account-1',
oldFileName,
TASK_STATUS.UPLOADED,
);
await createCheckoutPermissions(source, task.taskId, typistId);
// 事前にDBを確認
{
const audioFile = await getAudioFile(source, task.audioFileId);
expect(audioFile?.file_name).toBe(oldFileName);
expect(audioFile?.raw_file_name).toBe(oldFileName);
}
const newFileName = 'new.zip';
await service.fileRename(
context,
typistExternalId,
task.audioFileId,
newFileName,
);
//実行結果を確認
{
const audioFile = await getAudioFile(source, task.audioFileId);
expect(audioFile?.file_name).toBe(newFileName);
expect(audioFile?.raw_file_name).toBe(oldFileName);
}
});
it('ユーザーが管理者でなくRoleがNoneの場合、エラーとなること', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { account } = await makeTestAccount(source, { tier: 5 });
const { external_id: noneExternalId } = await makeTestUser(source, {
account_id: account.id,
external_id: 'none-user-external-id',
role: USER_ROLES.NONE,
});
const context = makeContext(noneExternalId, 'requestId');
const oldFileName = 'old.zip';
const task = await createTask(
source,
account.id,
'https://blob.url/account-1',
oldFileName,
TASK_STATUS.UPLOADED,
);
// 事前にDBを確認
{
const audioFile = await getAudioFile(source, task.audioFileId);
expect(audioFile?.file_name).toBe(oldFileName);
expect(audioFile?.raw_file_name).toBe(oldFileName);
}
const newFileName = 'new.zip';
try {
await service.fileRename(
context,
noneExternalId,
task.audioFileId,
newFileName,
);
fail();
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E021001'));
} else {
fail();
}
}
});
it('Authorがファイル名変更をするときユーザーのAuthorIDとタスクのAuthorIDが異なる場合、エラーとなること', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { account } = await makeTestAccount(source, { tier: 5 });
const { external_id: authorExternalId } = await makeTestUser(source, {
account_id: account.id,
external_id: 'author-user-external-id',
role: USER_ROLES.AUTHOR,
author_id: 'AUTHOR_ID',
});
const context = makeContext(authorExternalId, 'requestId');
const oldFileName = 'old.zip';
const task = await createTask(
source,
account.id,
'https://blob.url/account-1',
oldFileName,
TASK_STATUS.UPLOADED,
undefined,
'AUTHOR_ID_XXX',
);
// 事前にDBを確認
{
const audioFile = await getAudioFile(source, task.audioFileId);
expect(audioFile?.file_name).toBe(oldFileName);
expect(audioFile?.raw_file_name).toBe(oldFileName);
}
const newFileName = 'new.zip';
try {
await service.fileRename(
context,
authorExternalId,
task.audioFileId,
newFileName,
);
fail();
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E021001'));
} else {
fail();
}
}
});
it('Typistがファイル名変更をするときユーザーがタスクのチェックアウト候補でない場合、エラーとなること', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { account } = await makeTestAccount(source, { tier: 5 });
const { external_id: typistExternalId } = await makeTestUser(source, {
account_id: account.id,
external_id: 'typist-user-external-id',
role: USER_ROLES.TYPIST,
});
const context = makeContext(typistExternalId, 'requestId');
const oldFileName = 'old.zip';
const task = await createTask(
source,
account.id,
'https://blob.url/account-1',
oldFileName,
TASK_STATUS.UPLOADED,
);
// 事前にDBを確認
{
const audioFile = await getAudioFile(source, task.audioFileId);
expect(audioFile?.file_name).toBe(oldFileName);
expect(audioFile?.raw_file_name).toBe(oldFileName);
}
const newFileName = 'new.zip';
try {
await service.fileRename(
context,
typistExternalId,
task.audioFileId,
newFileName,
);
fail();
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E021001'));
} else {
fail();
}
}
});
it('変更するファイル名がすでに存在する場合、エラーとなること', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<FilesService>(FilesService);
// 第五階層のアカウント作成
const { account, admin } = await makeTestAccount(source, { tier: 5 });
const context = makeContext(admin.external_id, 'requestId');
const oldFileName = 'old.zip';
const task = await createTask(
source,
account.id,
'https://blob.url/account-1',
oldFileName,
TASK_STATUS.UPLOADED,
undefined,
undefined,
undefined,
undefined,
'00000001',
);
const alreadyExistFileName = 'already.zip';
const alreadyExistTask = await createTask(
source,
account.id,
'https://blob.url/account-1',
alreadyExistFileName,
TASK_STATUS.UPLOADED,
undefined,
undefined,
undefined,
undefined,
'00000002',
);
// 事前にDBを確認
{
const audioFile = await getAudioFile(source, task.audioFileId);
expect(audioFile?.file_name).toBe(oldFileName);
expect(audioFile?.raw_file_name).toBe(oldFileName);
const alreadyExistAudioFile = await getAudioFile(
source,
alreadyExistTask.audioFileId,
);
expect(alreadyExistAudioFile?.file_name).toBe(alreadyExistFileName);
}
try {
await service.fileRename(
context,
admin.external_id,
task.audioFileId,
alreadyExistFileName,
);
fail();
} catch (e) {
if (e instanceof HttpException) {
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
expect(e.getResponse()).toEqual(makeErrorResponse('E021002'));
} else {
fail();
}
}
});
});