Merged PR 335: API修正(アカウント登録)&テスト実装
## 概要 [Task2369: API修正(アカウント登録)&テスト実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2369) - リカバリ処理を実装 - テスト追加 ## レビューポイント - テストケースは足りているか - リカバリ処理を追加したが、漏れはないか ## UIの変更 - Before/Afterのスクショなど - スクショ置き場 ## 動作確認状況 - ローカルで確認 ## 補足 - 相談、参考資料などがあれば
This commit is contained in:
parent
76ed87d82a
commit
b8c2640719
@ -7,6 +7,8 @@ import { SendGridService } from '../../gateways/sendgrid/sendgrid.service';
|
|||||||
import { User, newUser } from '../../repositories/users/entity/user.entity';
|
import { User, newUser } from '../../repositories/users/entity/user.entity';
|
||||||
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
|
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
|
||||||
import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service';
|
import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service';
|
||||||
|
import { AccountsRepositoryService } from '../../repositories/accounts/accounts.repository.service';
|
||||||
|
import { Account } from '../../repositories/accounts/entity/account.entity';
|
||||||
|
|
||||||
// ### ユニットテスト用コード以外では絶対に使用してはいけないダーティな手段を使用しているが、他の箇所では使用しないこと ###
|
// ### ユニットテスト用コード以外では絶対に使用してはいけないダーティな手段を使用しているが、他の箇所では使用しないこと ###
|
||||||
|
|
||||||
@ -155,6 +157,11 @@ export const overrideBlobstorageService = <TService>(
|
|||||||
accountId: number,
|
accountId: number,
|
||||||
country: string,
|
country: string,
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
|
deleteContainer?: (
|
||||||
|
context: Context,
|
||||||
|
accountId: number,
|
||||||
|
country: string,
|
||||||
|
) => Promise<void>;
|
||||||
},
|
},
|
||||||
): void => {
|
): void => {
|
||||||
// テストコードでのみ許される強引な方法でprivateメンバ変数の参照を取得
|
// テストコードでのみ許される強引な方法でprivateメンバ変数の参照を取得
|
||||||
@ -165,4 +172,47 @@ export const overrideBlobstorageService = <TService>(
|
|||||||
writable: true,
|
writable: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (overrides.deleteContainer) {
|
||||||
|
Object.defineProperty(obj, obj.deleteContainer.name, {
|
||||||
|
value: overrides.deleteContainer,
|
||||||
|
writable: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* accountsRepositoryのモックを作成して、TServiceが依存するサービス(AccountsRepositoryService)の参照を上書きする
|
||||||
|
* ※ serviceに指定するオブジェクトは`accountsRepository: AccountsRepositoryService`メンバ変数を持つ必要がある
|
||||||
|
* @param service 上書きしたいTService
|
||||||
|
* @param overrides accountsRepositoryの各種メソッドのモックが返す値(省略した場合は本物のメソッドが呼ばれる)
|
||||||
|
*/
|
||||||
|
export const overrideAccountsRepositoryService = <TService>(
|
||||||
|
service: TService,
|
||||||
|
overrides: {
|
||||||
|
createAccount?: (
|
||||||
|
companyName: string,
|
||||||
|
country: string,
|
||||||
|
dealerAccountId: number | undefined,
|
||||||
|
tier: number,
|
||||||
|
adminExternalUserId: string,
|
||||||
|
adminUserRole: string,
|
||||||
|
adminUserAcceptedTermsVersion: string,
|
||||||
|
) => Promise<{ newAccount: Account; adminUser: User }>;
|
||||||
|
deleteAccount?: (accountId: number, userId: number) => Promise<void>;
|
||||||
|
},
|
||||||
|
): void => {
|
||||||
|
// テストコードでのみ許される強引な方法でprivateメンバ変数の参照を取得
|
||||||
|
const obj = (service as any).accountRepository as AccountsRepositoryService;
|
||||||
|
if (overrides.deleteAccount) {
|
||||||
|
Object.defineProperty(obj, obj.deleteAccount.name, {
|
||||||
|
value: overrides.deleteAccount,
|
||||||
|
writable: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (overrides.createAccount) {
|
||||||
|
Object.defineProperty(obj, obj.createAccount.name, {
|
||||||
|
value: overrides.createAccount,
|
||||||
|
writable: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -21,19 +21,23 @@ import {
|
|||||||
getUserFromExternalID,
|
getUserFromExternalID,
|
||||||
getAccounts,
|
getAccounts,
|
||||||
getUsers,
|
getUsers,
|
||||||
|
getSortCriteria,
|
||||||
createAccountAndAdminUser,
|
createAccountAndAdminUser,
|
||||||
} from './test/utility';
|
} from './test/utility';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { makeTestingModule } from '../../common/test/modules';
|
import { makeTestingModule } from '../../common/test/modules';
|
||||||
import { AccountsService } from './accounts.service';
|
import { AccountsService } from './accounts.service';
|
||||||
import { makeContext } from '../../common/log';
|
import { Context, makeContext } from '../../common/log';
|
||||||
import { TIERS } from '../../constants';
|
import { TIERS } from '../../constants';
|
||||||
import { License } from '../../repositories/licenses/entity/license.entity';
|
import { License } from '../../repositories/licenses/entity/license.entity';
|
||||||
import {
|
import {
|
||||||
|
overrideAccountsRepositoryService,
|
||||||
overrideAdB2cService,
|
overrideAdB2cService,
|
||||||
overrideBlobstorageService,
|
overrideBlobstorageService,
|
||||||
overrideSendgridService,
|
overrideSendgridService,
|
||||||
} from '../../common/test/overrides';
|
} from '../../common/test/overrides';
|
||||||
|
import { AdB2cService } from '../../gateways/adb2c/adb2c.service';
|
||||||
|
import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service';
|
||||||
|
|
||||||
describe('createAccount', () => {
|
describe('createAccount', () => {
|
||||||
let source: DataSource = null;
|
let source: DataSource = null;
|
||||||
@ -247,10 +251,10 @@ describe('createAccount', () => {
|
|||||||
expect(users.length).toBe(0);
|
expect(users.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('アカウントを作成がBlobStorageへの通信失敗によって失敗すると500エラーが発生する', async () => {
|
it('アカウントを作成がDBへの通信失敗によって500エラーが発生した場合、リカバリ処理としてADB2Cユーザーを削除され、500エラーが返却される', async () => {
|
||||||
const module = await makeTestingModule(source);
|
const module = await makeTestingModule(source);
|
||||||
const service = module.get<AccountsService>(AccountsService);
|
const service = module.get<AccountsService>(AccountsService);
|
||||||
|
const b2cService = module.get<AdB2cService>(AdB2cService);
|
||||||
const externalId = 'test_external_id';
|
const externalId = 'test_external_id';
|
||||||
const companyName = 'test_company_name';
|
const companyName = 'test_company_name';
|
||||||
const country = 'US';
|
const country = 'US';
|
||||||
@ -265,6 +269,135 @@ describe('createAccount', () => {
|
|||||||
createUser: async () => {
|
createUser: async () => {
|
||||||
return { sub: externalId };
|
return { sub: externalId };
|
||||||
},
|
},
|
||||||
|
deleteUser: jest.fn(),
|
||||||
|
});
|
||||||
|
overrideSendgridService(service, {});
|
||||||
|
|
||||||
|
overrideAccountsRepositoryService(service, {
|
||||||
|
createAccount: async () => {
|
||||||
|
throw new Error();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.createAccount(
|
||||||
|
makeContext('uuid'),
|
||||||
|
companyName,
|
||||||
|
country,
|
||||||
|
dealerAccountId,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
username,
|
||||||
|
role,
|
||||||
|
acceptedTermsVersion,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof HttpException) {
|
||||||
|
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||||||
|
} else {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// DB内が想定通りになっているか確認
|
||||||
|
// DBのデータ作成で失敗しているので、DB内は空
|
||||||
|
const accounts = await getAccounts(source);
|
||||||
|
expect(accounts.length).toBe(0);
|
||||||
|
const users = await getUsers(source);
|
||||||
|
expect(users.length).toBe(0);
|
||||||
|
const sortCriteria = await getSortCriteria(source);
|
||||||
|
expect(sortCriteria.length).toBe(0);
|
||||||
|
// ADB2Cユーザー削除メソッドが呼ばれているか確認
|
||||||
|
expect(b2cService.deleteUser).toBeCalledWith(
|
||||||
|
externalId,
|
||||||
|
makeContext('uuid'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('アカウントを作成がDBへの通信失敗によって500エラーが発生した場合、リカバリ処理が実行されるが、ADB2Cユーザー削除で失敗した場合、500エラーが返却される', async () => {
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
const service = module.get<AccountsService>(AccountsService);
|
||||||
|
const b2cService = module.get<AdB2cService>(AdB2cService);
|
||||||
|
const externalId = 'test_external_id';
|
||||||
|
const companyName = 'test_company_name';
|
||||||
|
const country = 'US';
|
||||||
|
const dealerAccountId = 1;
|
||||||
|
const email = 'dummy@dummy.dummy';
|
||||||
|
const password = 'dummy_password';
|
||||||
|
const username = 'dummy_username';
|
||||||
|
const role = 'none';
|
||||||
|
const acceptedTermsVersion = '1.0.0';
|
||||||
|
|
||||||
|
overrideAdB2cService(service, {
|
||||||
|
createUser: async () => {
|
||||||
|
return { sub: externalId };
|
||||||
|
},
|
||||||
|
deleteUser: jest.fn().mockRejectedValue(new Error()),
|
||||||
|
});
|
||||||
|
overrideSendgridService(service, {});
|
||||||
|
|
||||||
|
overrideAccountsRepositoryService(service, {
|
||||||
|
createAccount: async () => {
|
||||||
|
throw new Error();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.createAccount(
|
||||||
|
makeContext('uuid'),
|
||||||
|
companyName,
|
||||||
|
country,
|
||||||
|
dealerAccountId,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
username,
|
||||||
|
role,
|
||||||
|
acceptedTermsVersion,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof HttpException) {
|
||||||
|
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||||||
|
} else {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// DB内が想定通りになっているか確認
|
||||||
|
// DBのデータ作成で失敗しているので、DB内は空
|
||||||
|
const accounts = await getAccounts(source);
|
||||||
|
expect(accounts.length).toBe(0);
|
||||||
|
const users = await getUsers(source);
|
||||||
|
expect(users.length).toBe(0);
|
||||||
|
const sortCriteria = await getSortCriteria(source);
|
||||||
|
expect(sortCriteria.length).toBe(0);
|
||||||
|
// ADB2Cユーザー削除メソッドが呼ばれているか確認
|
||||||
|
expect(b2cService.deleteUser).toBeCalledWith(
|
||||||
|
externalId,
|
||||||
|
makeContext('uuid'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('アカウントを作成がBlobStorageへの通信失敗によって500エラーが発生した場合、リカバリ処理としてADB2C,DB上のデータが削除され、500エラーが返却される', async () => {
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
const service = module.get<AccountsService>(AccountsService);
|
||||||
|
const b2cService = module.get<AdB2cService>(AdB2cService);
|
||||||
|
b2cService.deleteUser = jest.fn(); // リカバリ処理の確認のため、deleteUserをモック化
|
||||||
|
const externalId = 'test_external_id';
|
||||||
|
const companyName = 'test_company_name';
|
||||||
|
const country = 'US';
|
||||||
|
const dealerAccountId = 1;
|
||||||
|
const email = 'dummy@dummy.dummy';
|
||||||
|
const password = 'dummy_password';
|
||||||
|
const username = 'dummy_username';
|
||||||
|
const role = 'none';
|
||||||
|
const acceptedTermsVersion = '1.0.0';
|
||||||
|
|
||||||
|
overrideAdB2cService(service, {
|
||||||
|
createUser: async () => {
|
||||||
|
return { sub: externalId };
|
||||||
|
},
|
||||||
|
deleteUser: async () => {
|
||||||
|
return;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
overrideSendgridService(service, {});
|
overrideSendgridService(service, {});
|
||||||
overrideBlobstorageService(service, {
|
overrideBlobstorageService(service, {
|
||||||
@ -290,9 +423,270 @@ describe('createAccount', () => {
|
|||||||
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||||||
} else {
|
} else {
|
||||||
expect(true).toBe(false); // ここには来てはいけない
|
fail();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// DB内が想定通りになっているか確認
|
||||||
|
// リカバリ処理が走っているため、アカウント・ユーザーは削除されている
|
||||||
|
const accounts = await getAccounts(source);
|
||||||
|
expect(accounts.length).toBe(0);
|
||||||
|
const users = await getUsers(source);
|
||||||
|
expect(users.length).toBe(0);
|
||||||
|
const sortCriteria = await getSortCriteria(source);
|
||||||
|
expect(sortCriteria.length).toBe(0);
|
||||||
|
// ADB2Cユーザー削除メソッドが呼ばれているか確認
|
||||||
|
expect(b2cService.deleteUser).toBeCalledWith(
|
||||||
|
externalId,
|
||||||
|
makeContext('uuid'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('アカウントを作成がBlobStorageへの通信失敗によって500エラーが発生した場合、リカバリ処理が実行されるが、そのリカバリ処理に失敗した場合、500エラーが返却される', async () => {
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
const service = module.get<AccountsService>(AccountsService);
|
||||||
|
const b2cService = module.get<AdB2cService>(AdB2cService);
|
||||||
|
const externalId = 'test_external_id';
|
||||||
|
const companyName = 'test_company_name';
|
||||||
|
const country = 'US';
|
||||||
|
const dealerAccountId = 1;
|
||||||
|
const email = 'dummy@dummy.dummy';
|
||||||
|
const password = 'dummy_password';
|
||||||
|
const username = 'dummy_username';
|
||||||
|
const role = 'none';
|
||||||
|
const acceptedTermsVersion = '1.0.0';
|
||||||
|
|
||||||
|
overrideAdB2cService(service, {
|
||||||
|
createUser: async () => {
|
||||||
|
return { sub: externalId };
|
||||||
|
},
|
||||||
|
deleteUser: jest.fn().mockRejectedValue(new Error()),
|
||||||
|
});
|
||||||
|
overrideSendgridService(service, {});
|
||||||
|
overrideBlobstorageService(service, {
|
||||||
|
createContainer: async () => {
|
||||||
|
throw new Error();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
overrideAccountsRepositoryService(service, {
|
||||||
|
deleteAccount: async () => {
|
||||||
|
throw new Error();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.createAccount(
|
||||||
|
makeContext('uuid'),
|
||||||
|
companyName,
|
||||||
|
country,
|
||||||
|
dealerAccountId,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
username,
|
||||||
|
role,
|
||||||
|
acceptedTermsVersion,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof HttpException) {
|
||||||
|
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||||||
|
} else {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// DB内が想定通りになっているか確認
|
||||||
|
// DB上のデータのリカバリ処理に失敗したため、DB上のデータは削除されない
|
||||||
|
const accounts = await getAccounts(source);
|
||||||
|
expect(accounts.length).toBe(1);
|
||||||
|
const users = await getUsers(source);
|
||||||
|
expect(users.length).toBe(1);
|
||||||
|
const sortCriteria = await getSortCriteria(source);
|
||||||
|
expect(sortCriteria.length).toBe(1);
|
||||||
|
// ADB2Cユーザー削除メソッドが呼ばれているか確認
|
||||||
|
expect(b2cService.deleteUser).toBeCalledWith(
|
||||||
|
externalId,
|
||||||
|
makeContext('uuid'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('アカウントを作成がSendGridへの通信失敗によって500エラーが発生した場合、リカバリ処理としてADB2C,DB上のデータとBlobストレージのコンテナが削除され、500エラーが返却される', async () => {
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
const service = module.get<AccountsService>(AccountsService);
|
||||||
|
const b2cService = module.get<AdB2cService>(AdB2cService);
|
||||||
|
const blobstorageService =
|
||||||
|
module.get<BlobstorageService>(BlobstorageService);
|
||||||
|
const externalId = 'test_external_id';
|
||||||
|
const companyName = 'test_company_name';
|
||||||
|
const country = 'US';
|
||||||
|
const dealerAccountId = 1;
|
||||||
|
const email = 'dummy@dummy.dummy';
|
||||||
|
const password = 'dummy_password';
|
||||||
|
const username = 'dummy_username';
|
||||||
|
const role = 'none';
|
||||||
|
const acceptedTermsVersion = '1.0.0';
|
||||||
|
|
||||||
|
overrideAdB2cService(service, {
|
||||||
|
createUser: async (
|
||||||
|
_context: Context,
|
||||||
|
_email: string,
|
||||||
|
_password: string,
|
||||||
|
_username: string,
|
||||||
|
) => {
|
||||||
|
// ユーザー作成時に指定したパラメータが正しく渡されていることを確認
|
||||||
|
expect(email).toEqual(_email);
|
||||||
|
expect(username).toEqual(_username);
|
||||||
|
|
||||||
|
return { sub: externalId };
|
||||||
|
},
|
||||||
|
deleteUser: jest.fn(),
|
||||||
|
});
|
||||||
|
overrideSendgridService(service, {
|
||||||
|
sendMail: async () => {
|
||||||
|
throw new Error();
|
||||||
|
},
|
||||||
|
createMailContentFromEmailConfirm: async () => {
|
||||||
|
return {
|
||||||
|
html: 'dummy_html',
|
||||||
|
subject: 'dummy_subject',
|
||||||
|
text: 'dummy_text',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
overrideBlobstorageService(service, {
|
||||||
|
createContainer: async () => {
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
deleteContainer: jest.fn(),
|
||||||
|
});
|
||||||
|
overrideAccountsRepositoryService(service, {});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.createAccount(
|
||||||
|
makeContext('uuid'),
|
||||||
|
companyName,
|
||||||
|
country,
|
||||||
|
dealerAccountId,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
username,
|
||||||
|
role,
|
||||||
|
acceptedTermsVersion,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof HttpException) {
|
||||||
|
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||||||
|
} else {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// DB内が想定通りになっているか確認
|
||||||
|
// リカバリ処理によってADB2C,DB上のデータとBlobストレージのコンテナが削除される
|
||||||
|
const accounts = await getAccounts(source);
|
||||||
|
expect(accounts.length).toBe(0);
|
||||||
|
const users = await getUsers(source);
|
||||||
|
expect(users.length).toBe(0);
|
||||||
|
const sortCriteria = await getSortCriteria(source);
|
||||||
|
expect(sortCriteria.length).toBe(0);
|
||||||
|
// ADB2Cユーザー削除メソッドが呼ばれているか確認
|
||||||
|
expect(b2cService.deleteUser).toBeCalledWith(
|
||||||
|
externalId,
|
||||||
|
makeContext('uuid'),
|
||||||
|
);
|
||||||
|
// Blobストレージのコンテナ削除メソッドが呼ばれているか確認
|
||||||
|
expect(blobstorageService.deleteContainer).toBeCalledWith(
|
||||||
|
makeContext('uuid'),
|
||||||
|
1, //新規作成したアカウントのID
|
||||||
|
country,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('アカウントを作成がSendGridへの通信失敗によって500エラーが発生した場合、リカバリ処理が実行されるが、そのリカバリ処理に失敗した場合、500エラーが返却される', async () => {
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
const service = module.get<AccountsService>(AccountsService);
|
||||||
|
const b2cService = module.get<AdB2cService>(AdB2cService);
|
||||||
|
const blobstorageService =
|
||||||
|
module.get<BlobstorageService>(BlobstorageService);
|
||||||
|
const externalId = 'test_external_id';
|
||||||
|
const companyName = 'test_company_name';
|
||||||
|
const country = 'US';
|
||||||
|
const dealerAccountId = 1;
|
||||||
|
const email = 'dummy@dummy.dummy';
|
||||||
|
const password = 'dummy_password';
|
||||||
|
const username = 'dummy_username';
|
||||||
|
const role = 'none';
|
||||||
|
const acceptedTermsVersion = '1.0.0';
|
||||||
|
|
||||||
|
overrideAdB2cService(service, {
|
||||||
|
createUser: async () => {
|
||||||
|
return { sub: externalId };
|
||||||
|
},
|
||||||
|
deleteUser: jest.fn().mockRejectedValue(new Error()),
|
||||||
|
});
|
||||||
|
overrideSendgridService(service, {
|
||||||
|
sendMail: async () => {
|
||||||
|
throw new Error();
|
||||||
|
},
|
||||||
|
createMailContentFromEmailConfirm: async () => {
|
||||||
|
return {
|
||||||
|
html: 'dummy_html',
|
||||||
|
subject: 'dummy_subject',
|
||||||
|
text: 'dummy_text',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
overrideBlobstorageService(service, {
|
||||||
|
createContainer: async () => {
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
deleteContainer: jest
|
||||||
|
.fn()
|
||||||
|
.mockRejectedValue(new Error('BlobStorage Error')),
|
||||||
|
});
|
||||||
|
overrideAccountsRepositoryService(service, {
|
||||||
|
deleteAccount: async () => {
|
||||||
|
throw new Error();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.createAccount(
|
||||||
|
makeContext('uuid'),
|
||||||
|
companyName,
|
||||||
|
country,
|
||||||
|
dealerAccountId,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
username,
|
||||||
|
role,
|
||||||
|
acceptedTermsVersion,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof HttpException) {
|
||||||
|
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||||||
|
} else {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// DB内が想定通りになっているか確認
|
||||||
|
// リカバリ処理によってADB2C,DB上のデータとBlobストレージのコンテナが削除されない
|
||||||
|
const accounts = await getAccounts(source);
|
||||||
|
expect(accounts.length).toBe(1);
|
||||||
|
const users = await getUsers(source);
|
||||||
|
expect(users.length).toBe(1);
|
||||||
|
const sortCriteria = await getSortCriteria(source);
|
||||||
|
expect(sortCriteria.length).toBe(1);
|
||||||
|
// ADB2Cユーザー削除メソッドが呼ばれているか確認
|
||||||
|
expect(b2cService.deleteUser).toBeCalledWith(
|
||||||
|
externalId,
|
||||||
|
makeContext('uuid'),
|
||||||
|
);
|
||||||
|
// Blobストレージのコンテナ削除メソッドが呼ばれているか確認
|
||||||
|
expect(blobstorageService.deleteContainer).toBeCalledWith(
|
||||||
|
makeContext('uuid'),
|
||||||
|
1, //新規作成したアカウントのID
|
||||||
|
country,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -190,9 +190,10 @@ export class AccountsService {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.error(`error=${e}`);
|
this.logger.error(`error=${e}`);
|
||||||
this.logger.error('create account failed');
|
this.logger.error('create account failed');
|
||||||
this.logger.error(
|
//リカバリ処理
|
||||||
`[NOT IMPLEMENT] [RECOVER] delete account: ${externalUser.sub}`,
|
// idpのユーザーを削除
|
||||||
);
|
await this.deleteAdB2cUser(externalUser.sub, context);
|
||||||
|
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
makeErrorResponse('E009999'),
|
makeErrorResponse('E009999'),
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
@ -209,6 +210,13 @@ export class AccountsService {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.error(`error=${e}`);
|
this.logger.error(`error=${e}`);
|
||||||
this.logger.error('create container failed');
|
this.logger.error('create container failed');
|
||||||
|
//リカバリ処理
|
||||||
|
// idpのユーザーを削除
|
||||||
|
await this.deleteAdB2cUser(externalUser.sub, context);
|
||||||
|
|
||||||
|
// DBのアカウントを削除
|
||||||
|
await this.deleteAccount(account.id, user.id, context);
|
||||||
|
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
makeErrorResponse('E009999'),
|
makeErrorResponse('E009999'),
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
@ -238,16 +246,18 @@ export class AccountsService {
|
|||||||
html,
|
html,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
|
||||||
this.logger.error(`error=${e}`);
|
this.logger.error(`error=${e}`);
|
||||||
this.logger.error('create user failed');
|
this.logger.error('send E-mail failed');
|
||||||
this.logger.error(
|
//リカバリ処理
|
||||||
`[NOT IMPLEMENT] [RECOVER] delete account: ${account.id}`,
|
// idpのユーザーを削除
|
||||||
);
|
await this.deleteAdB2cUser(externalUser.sub, context);
|
||||||
this.logger.error(
|
|
||||||
`[NOT IMPLEMENT] [RECOVER] delete externalUser: ${externalUser.sub}`,
|
// DBのアカウントを削除
|
||||||
);
|
await this.deleteAccount(account.id, user.id, context);
|
||||||
this.logger.error(`[NOT IMPLEMENT] [RECOVER] delete user: ${user.id}`);
|
|
||||||
|
// Blobコンテナを削除
|
||||||
|
await this.deleteBlobContainer(account.id, country, context);
|
||||||
|
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
makeErrorResponse('E009999'),
|
makeErrorResponse('E009999'),
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
@ -268,6 +278,67 @@ export class AccountsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AdB2cのユーザーを削除
|
||||||
|
// TODO「タスク 2452: リトライ処理を入れる箇所を検討し、実装する」の候補
|
||||||
|
private async deleteAdB2cUser(
|
||||||
|
externalUserId: string,
|
||||||
|
context: Context,
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this.adB2cService.deleteUser(externalUserId, context);
|
||||||
|
this.logger.log(
|
||||||
|
`[${context.trackingId}] delete externalUser: ${externalUserId}`,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(`error=${error}`);
|
||||||
|
this.logger.error(
|
||||||
|
`[MANUAL_RECOVERY_REQUIRED] [${context.trackingId}] Failed to delete externalUser: ${externalUserId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBのアカウントを削除
|
||||||
|
private async deleteAccount(
|
||||||
|
accountId: number,
|
||||||
|
userId: number,
|
||||||
|
context: Context,
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this.accountRepository.deleteAccount(accountId, userId);
|
||||||
|
this.logger.log(
|
||||||
|
`[${context.trackingId}] delete account: ${accountId}, user: ${userId}`,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(`error=${error}`);
|
||||||
|
this.logger.error(
|
||||||
|
`[MANUAL_RECOVERY_REQUIRED] [${context.trackingId}] Failed to delete account: ${accountId}, user: ${userId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blobコンテナを削除
|
||||||
|
// TODO「タスク 2452: リトライ処理を入れる箇所を検討し、実装する」の候補
|
||||||
|
private async deleteBlobContainer(
|
||||||
|
accountId: number,
|
||||||
|
country: string,
|
||||||
|
context: Context,
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this.blobStorageService.deleteContainer(
|
||||||
|
context,
|
||||||
|
accountId,
|
||||||
|
country,
|
||||||
|
);
|
||||||
|
this.logger.log(
|
||||||
|
`[${context.trackingId}] delete container: ${accountId}, country: ${country}`,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(
|
||||||
|
`[MANUAL_RECOVERY_REQUIRED] [${context.trackingId}] Failed to delete container: ${accountId}, country: ${country}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* アクセストークンからアカウント情報を取得する
|
* アクセストークンからアカウント情報を取得する
|
||||||
* @param token
|
* @param token
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import {
|
|||||||
License,
|
License,
|
||||||
LicenseOrder,
|
LicenseOrder,
|
||||||
} from '../../../repositories/licenses/entity/license.entity';
|
} from '../../../repositories/licenses/entity/license.entity';
|
||||||
|
import { SortCriteria } from '../../../repositories/sort_criteria/entity/sort_criteria.entity';
|
||||||
|
|
||||||
// TODO: [PBI 2379] 他のUtilityからコピペしてきたもの。後日整理される前提。
|
// TODO: [PBI 2379] 他のUtilityからコピペしてきたもの。後日整理される前提。
|
||||||
export const createAccountAndAdminUser = async (
|
export const createAccountAndAdminUser = async (
|
||||||
@ -162,6 +163,15 @@ export const getUsers = async (dataSource: DataSource): Promise<User[]> => {
|
|||||||
return await dataSource.getRepository(User).find();
|
return await dataSource.getRepository(User).find();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* テスト ユーティリティ: すべてのソート条件を取得する
|
||||||
|
* @param dataSource データソース
|
||||||
|
* @returns 該当ソート条件一覧
|
||||||
|
*/
|
||||||
|
export const getSortCriteria = async (dataSource: DataSource) => {
|
||||||
|
return await dataSource.getRepository(SortCriteria).find();
|
||||||
|
};
|
||||||
|
|
||||||
export const createLicense = async (
|
export const createLicense = async (
|
||||||
datasource: DataSource,
|
datasource: DataSource,
|
||||||
accountId: number,
|
accountId: number,
|
||||||
|
|||||||
@ -160,14 +160,14 @@ export class AccountsRepositoryService {
|
|||||||
const accountsRepo = entityManager.getRepository(Account);
|
const accountsRepo = entityManager.getRepository(Account);
|
||||||
const usersRepo = entityManager.getRepository(User);
|
const usersRepo = entityManager.getRepository(User);
|
||||||
const sortCriteriaRepo = entityManager.getRepository(SortCriteria);
|
const sortCriteriaRepo = entityManager.getRepository(SortCriteria);
|
||||||
// アカウントを削除
|
|
||||||
await accountsRepo.delete({ id: accountId });
|
|
||||||
// プライマリ管理者を削除
|
|
||||||
await usersRepo.delete({ id: userId });
|
|
||||||
// ソート条件を削除
|
// ソート条件を削除
|
||||||
await sortCriteriaRepo.delete({
|
await sortCriteriaRepo.delete({
|
||||||
user_id: userId,
|
user_id: userId,
|
||||||
});
|
});
|
||||||
|
// プライマリ管理者を削除
|
||||||
|
await usersRepo.delete({ id: userId });
|
||||||
|
// アカウントを削除
|
||||||
|
await accountsRepo.delete({ id: accountId });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user