From 9a28d92270b8ff6ac9d24d267e45c1e861030f5f Mon Sep 17 00:00:00 2001 From: donghun1214 Date: Fri, 8 Nov 2024 17:21:40 +0000 Subject: [PATCH] feat(infra): ready for load test --- .../apps/client/src/user/user.service.ts | 76 ++++++++++++++++++- .../codedang/codedang_service_admin.tf | 3 + .../codedang/codedang_service_client.tf | 3 + .../container_definitions/admin_api.json | 12 +++ .../container_definitions/client_api.json | 12 +++ apps/infra/production/codedang/variables.tf | 3 + 6 files changed, 108 insertions(+), 1 deletion(-) diff --git a/apps/backend/apps/client/src/user/user.service.ts b/apps/backend/apps/client/src/user/user.service.ts index 3e1485b828..92faeddd32 100644 --- a/apps/backend/apps/client/src/user/user.service.ts +++ b/apps/backend/apps/client/src/user/user.service.ts @@ -6,7 +6,7 @@ import type { User, UserProfile } from '@prisma/client' import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library' import { hash } from 'argon2' import { Cache } from 'cache-manager' -import { randomInt } from 'crypto' +import { randomInt, randomUUID } from 'crypto' import type { Request } from 'express' import { generate } from 'generate-password' import { ExtractJwt } from 'passport-jwt' @@ -80,6 +80,11 @@ export class UserService { } async sendPinForRegisterNewEmail({ email }: UserEmailDto): Promise { + // TODO: load test를 위함, 테스트 후 삭제 예정 + if (email === this.config.get('EMAIL_FOR_LOAD_TEST')) { + this.logger.debug('load test - sendPinForRegisterNewEmail') + return this.createPinAndSendEmail(email) + } const duplicatedUser = await this.getUserCredentialByEmail(email) if (duplicatedUser) { this.logger.debug('email duplicated') @@ -108,6 +113,11 @@ export class UserService { } async createPinAndSendEmail(email: string): Promise { + // TODO: load test를 위함, 테스트 후 삭제 예정 + if (email === this.config.get('EMAIL_FOR_LOAD_TEST')) { + this.logger.debug('load test - createPinAndSendEmail') + return 'You entered an email for testing' + } const pin = this.createPinRandomly(6) await this.emailService.sendEmailAuthenticationPin(email, pin) @@ -206,6 +216,14 @@ export class UserService { pin, email }: EmailAuthenticationPinDto): Promise { + // TODO: load test를 위함, 테스트 후 삭제 예정 + if (pin === this.config.get('PIN_FOR_LOAD_TEST')) { + this.logger.debug('load test - verifyPinAndIssueJwt') + const payload: EmailAuthJwtPayload = { email } + const token = await this.createJwt(payload) + + return token + } await this.verifyPin(pin, email) const payload: EmailAuthJwtPayload = { email } @@ -255,8 +273,59 @@ export class UserService { this.logger.debug({ jwt }, 'createJwt') return jwt } + /** TODO: load test를 위함, 테스트 후 삭제 예정 */ + async signUpForLoadTest(signUpDto: SignUpDto) { + const newSignUpDto: SignUpDto = { + ...signUpDto, + username: signUpDto.username + randomUUID(), + email: signUpDto.email + randomUUID() + } + + const duplicatedUser = await this.prisma.user.findUnique({ + where: { + username: newSignUpDto.username + } + }) + if (duplicatedUser) { + this.logger.debug('username duplicated') + throw new DuplicateFoundException('Username') + } + + if (!this.isValidUsername(signUpDto.username)) { + this.logger.debug('signUp - fail (invalid username)') + throw new UnprocessableDataException('Bad username') + } else if (!this.isValidPassword(signUpDto.password)) { + this.logger.debug('signUp - fail (invalid password)') + throw new UnprocessableDataException('Bad password') + } + try { + await this.deletePinFromCache( + emailAuthenticationPinCacheKey(newSignUpDto.email) + ) + } catch (e) { + // pass + } + + const user: User = await this.createUser(newSignUpDto) + const CreateUserProfileData: CreateUserProfileData = { + userId: user.id, + realName: signUpDto.realName + } + await this.createUserProfile(CreateUserProfileData) + await this.registerUserToPublicGroup(user.id) + + return user + } async signUp(req: Request, signUpDto: SignUpDto) { + // TODO: load test를 위함, 테스트 후 삭제 예정 + if ( + signUpDto.email === this.config.get('EMAIL_FOR_LOAD_TEST') || + signUpDto.username === this.config.get('USERNAME_FOR_LOAD_TEST') + ) { + this.logger.debug('load test - sign up') + return await this.signUpForLoadTest(signUpDto) + } const { email } = await this.verifyJwtFromRequestHeader(req) if (email != signUpDto.email) { this.logger.debug( @@ -545,6 +614,11 @@ export class UserService { } async checkDuplicatedUsername(usernameDto: UsernameDto) { + // TODO: load test를 위함, 테스트 후 삭제 예정 + if (usernameDto.username === this.config.get('USERNAME_FOR_LOAD_TEST')) { + this.logger.debug('load test - checkDuplicatedUsername') + return + } const duplicatedUser = await this.prisma.user.findUnique({ where: { username: usernameDto.username diff --git a/apps/infra/production/codedang/codedang_service_admin.tf b/apps/infra/production/codedang/codedang_service_admin.tf index 61f8022f61..2c68170c0d 100644 --- a/apps/infra/production/codedang/codedang_service_admin.tf +++ b/apps/infra/production/codedang/codedang_service_admin.tf @@ -68,6 +68,9 @@ module "admin_api" { media_secret_key = var.media_secret_key, otel_exporter_otlp_endpoint_url = var.otel_exporter_otlp_endpoint_url, loki_url = var.loki_url, + username_for_load_test = var.username_for_load_test, + email_for_load_test = var.email_for_load_test, + pin_for_load_test = var.pin_for_load_test })), jsondecode(file("container_definitions/log_router.json")) ]) diff --git a/apps/infra/production/codedang/codedang_service_client.tf b/apps/infra/production/codedang/codedang_service_client.tf index ad7e03d6d3..28147ed7c2 100644 --- a/apps/infra/production/codedang/codedang_service_client.tf +++ b/apps/infra/production/codedang/codedang_service_client.tf @@ -73,6 +73,9 @@ module "client_api" { kakao_client_secret = var.kakao_client_secret, otel_exporter_otlp_endpoint_url = var.otel_exporter_otlp_endpoint_url, loki_url = var.loki_url, + username_for_load_test = var.username_for_load_test, + email_for_load_test = var.email_for_load_test, + pin_for_load_test = var.pin_for_load_test })), jsondecode(file("container_definitions/log_router.json")) ]) diff --git a/apps/infra/production/codedang/container_definitions/admin_api.json b/apps/infra/production/codedang/container_definitions/admin_api.json index 22bb4c03bd..da1848b8cf 100644 --- a/apps/infra/production/codedang/container_definitions/admin_api.json +++ b/apps/infra/production/codedang/container_definitions/admin_api.json @@ -57,6 +57,18 @@ { "name": "OTEL_EXPORTER_OTLP_ENDPOINT_URL", "value": "${otel_exporter_otlp_endpoint_url}" + }, + { + "name": "USERNAME_FOR_LOAD_TEST", + "value": "${username_for_load_test}" + }, + { + "name": "EMAIL_FOR_LOAD_TEST", + "value": "${email_for_load_test}" + }, + { + "name": "PIN_FOR_LOAD_TEST", + "value": "${pin_for_load_test}" } ], "logConfiguration": { diff --git a/apps/infra/production/codedang/container_definitions/client_api.json b/apps/infra/production/codedang/container_definitions/client_api.json index 1fc90fd910..6d6f23ba0a 100644 --- a/apps/infra/production/codedang/container_definitions/client_api.json +++ b/apps/infra/production/codedang/container_definitions/client_api.json @@ -77,6 +77,18 @@ { "name": "OTEL_EXPORTER_OTLP_ENDPOINT_URL", "value": "${otel_exporter_otlp_endpoint_url}" + }, + { + "name": "USERNAME_FOR_LOAD_TEST", + "value": "${username_for_load_test}" + }, + { + "name": "EMAIL_FOR_LOAD_TEST", + "value": "${email_for_load_test}" + }, + { + "name": "PIN_FOR_LOAD_TEST", + "value": "${pin_for_load_test}" } ], "logConfiguration": { diff --git a/apps/infra/production/codedang/variables.tf b/apps/infra/production/codedang/variables.tf index 24c7e3799c..1bb3f6effa 100644 --- a/apps/infra/production/codedang/variables.tf +++ b/apps/infra/production/codedang/variables.tf @@ -26,6 +26,9 @@ variable "kakao_client_id" { sensitive = true } variable "kakao_client_secret" { sensitive = true } variable "otel_exporter_otlp_endpoint_url" { sensitive = true } variable "loki_url" { sensitive = true } +variable "username_for_load_test" { sensitive = true } +variable "email_for_load_test" { sensitive = true } +variable "pin_for_load_test" { sensitive = true } variable "testcase_bucket_name" { sensitive = true } variable "testcase_access_key" { sensitive = true }