diff --git a/src/main/kotlin/cc/rits/membership/console/paymaster/auth/ApplicationAuthenticationFetcher.kt b/src/main/kotlin/cc/rits/membership/console/paymaster/auth/ApplicationAuthenticationFetcher.kt index d9d0427..2263d4a 100644 --- a/src/main/kotlin/cc/rits/membership/console/paymaster/auth/ApplicationAuthenticationFetcher.kt +++ b/src/main/kotlin/cc/rits/membership/console/paymaster/auth/ApplicationAuthenticationFetcher.kt @@ -11,7 +11,7 @@ import io.micronaut.security.filters.AuthenticationFetcher import jakarta.inject.Singleton import org.reactivestreams.Publisher import reactor.core.publisher.Mono -import java.util.Base64 +import java.util.* /** * AuthenticationFetcher @@ -35,7 +35,8 @@ class ApplicationAuthenticationFetcher : AuthenticationFetcher { val authorizationInfo = Base64.getDecoder().decode(authorization) val userInfoResponse = ObjectMapper().readValue(authorizationInfo, UserInfoResponse::class.java) val roles = userInfoResponse.roles - emitter.success(Authentication.build(userInfoResponse.id.toString(), roles)) + val attributes = mapOf("userInfo" to userInfoResponse) + emitter.success(Authentication.build(userInfoResponse.id.toString(), roles, attributes)) } catch (exception: JsonProcessingException) { emitter.error(UnauthorizedException(ErrorCode.USER_NOT_LOGGED_IN)) } diff --git a/src/main/kotlin/cc/rits/membership/console/paymaster/domain/model/PurchaseRequestModel.kt b/src/main/kotlin/cc/rits/membership/console/paymaster/domain/model/PurchaseRequestModel.kt index a019a5a..486222f 100644 --- a/src/main/kotlin/cc/rits/membership/console/paymaster/domain/model/PurchaseRequestModel.kt +++ b/src/main/kotlin/cc/rits/membership/console/paymaster/domain/model/PurchaseRequestModel.kt @@ -11,7 +11,7 @@ class PurchaseRequestModel( /** * 購入申請ID */ - val id: UUID, + val id: UUID = UUID.randomUUID(), /** * 申請品名 @@ -51,6 +51,6 @@ class PurchaseRequestModel( /** * 申請日時 */ - val requestedAt: LocalDateTime + val requestedAt: LocalDateTime = LocalDateTime.now() ) diff --git a/src/main/kotlin/cc/rits/membership/console/paymaster/domain/repository/PurchaseRequestRepository.kt b/src/main/kotlin/cc/rits/membership/console/paymaster/domain/repository/PurchaseRequestRepository.kt index 7e32392..06ea10f 100644 --- a/src/main/kotlin/cc/rits/membership/console/paymaster/domain/repository/PurchaseRequestRepository.kt +++ b/src/main/kotlin/cc/rits/membership/console/paymaster/domain/repository/PurchaseRequestRepository.kt @@ -7,6 +7,11 @@ import java.util.* * 購入申請リポジトリ */ interface PurchaseRequestRepository { + /** + * 購入申請を登録 + */ + fun insert(purchaseRequestModel: PurchaseRequestModel) + /** * idから購入申請を取得 */ diff --git a/src/main/kotlin/cc/rits/membership/console/paymaster/exception/ErrorCode.kt b/src/main/kotlin/cc/rits/membership/console/paymaster/exception/ErrorCode.kt index 9b419cb..de069fc 100644 --- a/src/main/kotlin/cc/rits/membership/console/paymaster/exception/ErrorCode.kt +++ b/src/main/kotlin/cc/rits/membership/console/paymaster/exception/ErrorCode.kt @@ -7,6 +7,15 @@ enum class ErrorCode(val code: Int, val message: String) { /** * 30000~30999: 400 Bad Request */ + INVALID_PURCHASE_REQUEST_NAME_LENGTH(30000, "購入申請品名は1文字以上255文字以下である必要があります。"), + + INVALID_PURCHASE_REQUEST_DESCRIPTION_LENGTH(30001, "購入申請の説明文は1文字以上1023文字以下である必要があります。"), + + INVALID_PURCHASE_REQUEST_PRICE(30002, "購入申請品の単価は1円以上である必要があります。"), + + INVALID_PURCHASE_REQUEST_QUANTITY(30003, "購入申請品の個数は1個以上である必要があります。"), + + INVALID_PURCHASE_REQUEST_URL_LENGTH(30004, "購入申請品名のURLは1文字以上1023文字以下である必要があります。"), /** * 31000~31999: 401 Unauthorized diff --git a/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/api/controller/PurchaseRequestRestController.kt b/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/api/controller/PurchaseRequestRestController.kt index 1f5c8cd..cf1834f 100644 --- a/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/api/controller/PurchaseRequestRestController.kt +++ b/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/api/controller/PurchaseRequestRestController.kt @@ -1,16 +1,23 @@ package cc.rits.membership.console.paymaster.infrastructure.api.controller +import cc.rits.membership.console.paymaster.annotation.RequestValidation +import cc.rits.membership.console.paymaster.infrastructure.api.request.UpsertPurchaseRequestRequest import cc.rits.membership.console.paymaster.infrastructure.api.response.PurchaseRequestResponse import cc.rits.membership.console.paymaster.infrastructure.api.response.PurchaseRequestsResponse +import cc.rits.membership.console.paymaster.usecase.purchase_request.CreatePurchaseRequestUseCase import cc.rits.membership.console.paymaster.usecase.purchase_request.GetPurchaseRequestUseCase import cc.rits.membership.console.paymaster.usecase.purchase_request.GetPurchaseRequestsUseCase import io.micronaut.http.annotation.Controller import io.micronaut.http.annotation.Get import io.micronaut.http.annotation.PathVariable +import io.micronaut.http.annotation.Post import io.micronaut.scheduling.TaskExecutors import io.micronaut.scheduling.annotation.ExecuteOn import io.micronaut.security.annotation.Secured +import io.micronaut.security.authentication.Authentication import io.micronaut.security.rules.SecurityRule +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.parameters.RequestBody import io.swagger.v3.oas.annotations.tags.Tag import java.util.* @@ -21,10 +28,24 @@ import java.util.* @Controller("/api/purchase-requests") @Secured(SecurityRule.IS_AUTHENTICATED) @ExecuteOn(TaskExecutors.IO) -class PurchaseRequestRestController( +open class PurchaseRequestRestController( + private val createPurchaseRequestUseCase: CreatePurchaseRequestUseCase, private val getPurchaseRequestsUseCase: GetPurchaseRequestsUseCase, private val getPurchaseRequestUseCase: GetPurchaseRequestUseCase ) { + /** + * 購入申請作成API + * + * @param requestBody 購入申請作成リクエスト + * @param authentication 認証情報 + */ + @Post + open fun createPurchaseRequest( // + @RequestBody @RequestValidation requestBody: UpsertPurchaseRequestRequest, // + @Parameter(hidden = true) authentication: Authentication // + ) { + createPurchaseRequestUseCase.handle(authentication, requestBody) + } /** * 購入申請リスト取得API diff --git a/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/api/request/UpsertPurchaseRequestRequest.kt b/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/api/request/UpsertPurchaseRequestRequest.kt new file mode 100644 index 0000000..fbae76f --- /dev/null +++ b/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/api/request/UpsertPurchaseRequestRequest.kt @@ -0,0 +1,60 @@ +package cc.rits.membership.console.paymaster.infrastructure.api.request + +import cc.rits.membership.console.paymaster.exception.BadRequestException +import cc.rits.membership.console.paymaster.exception.ErrorCode +import cc.rits.membership.console.paymaster.util.ValidationUtil +import io.micronaut.core.annotation.Introspected + +/** + * 購入申請作成リクエスト + */ +@Introspected +class UpsertPurchaseRequestRequest( + /** + * 申請品名 + */ + val name: String, + + /** + * 説明 + */ + val description: String, + + /** + * 単価 + */ + val price: Int, + + /** + * 個数 + */ + val quantity: Int, + + /** + * URL + */ + val url: String + +) : BaseRequest() { + override fun validate() { + if (!ValidationUtil.checkStringLength(name, 1, 255)) { + throw BadRequestException(ErrorCode.INVALID_PURCHASE_REQUEST_NAME_LENGTH) + } + + if (!ValidationUtil.checkStringLength(description, 1, 1023)) { + throw BadRequestException(ErrorCode.INVALID_PURCHASE_REQUEST_DESCRIPTION_LENGTH) + } + + if (!ValidationUtil.checkNumberLength(price, 1, Int.MAX_VALUE)) { + throw BadRequestException(ErrorCode.INVALID_PURCHASE_REQUEST_PRICE) + } + + if (!ValidationUtil.checkNumberLength(quantity, 1, Int.MAX_VALUE)) { + throw BadRequestException(ErrorCode.INVALID_PURCHASE_REQUEST_QUANTITY) + } + + if (!ValidationUtil.checkStringLength(url, 1, 1023)) { + throw BadRequestException(ErrorCode.INVALID_PURCHASE_REQUEST_URL_LENGTH) + } + } +} diff --git a/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/data/entity/PurchaseRequestEntity.kt b/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/data/entity/PurchaseRequestEntity.kt index d9c1cea..6b8d0c4 100644 --- a/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/data/entity/PurchaseRequestEntity.kt +++ b/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/data/entity/PurchaseRequestEntity.kt @@ -1,6 +1,5 @@ package cc.rits.membership.console.paymaster.infrastructure.data.entity -import io.micronaut.data.annotation.GeneratedValue import io.micronaut.data.annotation.Id import io.micronaut.data.annotation.MappedEntity import java.time.LocalDateTime @@ -9,7 +8,6 @@ import java.util.* @MappedEntity(value = "purchase_request") data class PurchaseRequestEntity( @Id - @GeneratedValue val id: UUID, val name: String, diff --git a/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/data/respository_impl/PurchaseRequestQuery.kt b/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/data/respository_impl/PurchaseRequestQuery.kt index 2e74441..353b697 100644 --- a/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/data/respository_impl/PurchaseRequestQuery.kt +++ b/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/data/respository_impl/PurchaseRequestQuery.kt @@ -8,6 +8,7 @@ import java.util.* @JdbcRepository(dialect = Dialect.POSTGRES) abstract class PurchaseRequestQuery : GenericRepository { + abstract fun save(purchaseRequestEntity: PurchaseRequestEntity) abstract fun findById(id: UUID): PurchaseRequestEntity? diff --git a/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/data/respository_impl/PurchaseRequestRepositoryImpl.kt b/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/data/respository_impl/PurchaseRequestRepositoryImpl.kt index be62629..f950f04 100644 --- a/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/data/respository_impl/PurchaseRequestRepositoryImpl.kt +++ b/src/main/kotlin/cc/rits/membership/console/paymaster/infrastructure/data/respository_impl/PurchaseRequestRepositoryImpl.kt @@ -7,6 +7,7 @@ import cc.rits.membership.console.paymaster.enums.PurchaseRequestStatus import cc.rits.membership.console.paymaster.exception.ErrorCode import cc.rits.membership.console.paymaster.exception.InternalServerErrorException import cc.rits.membership.console.paymaster.factory.UserFactory +import cc.rits.membership.console.paymaster.infrastructure.data.entity.PurchaseRequestEntity import cc.rits.membership.console.paymaster.util.AuthUtil import jakarta.inject.Singleton import java.util.* @@ -18,6 +19,21 @@ class PurchaseRequestRepositoryImpl( private val userFactory: UserFactory, private val authUtil: AuthUtil ) : PurchaseRequestRepository { + override fun insert(purchaseRequestModel: PurchaseRequestModel) { + val purchaseRequestEntity = PurchaseRequestEntity( + id = purchaseRequestModel.id, + name = purchaseRequestModel.name, + description = purchaseRequestModel.description, + price = purchaseRequestModel.price, + quantity = purchaseRequestModel.quantity, + url = purchaseRequestModel.url, + status = purchaseRequestModel.status.id, + requestedBy = purchaseRequestModel.requestedBy!!.id, + requestedAt = purchaseRequestModel.requestedAt + ) + + purchaseRequestQuery.save(purchaseRequestEntity) + } override fun findById(id: UUID): PurchaseRequestModel? { return purchaseRequestQuery.findById(id)?.let { diff --git a/src/main/kotlin/cc/rits/membership/console/paymaster/usecase/purchase_request/CreatePurchaseRequestUseCase.kt b/src/main/kotlin/cc/rits/membership/console/paymaster/usecase/purchase_request/CreatePurchaseRequestUseCase.kt new file mode 100644 index 0000000..e5ab379 --- /dev/null +++ b/src/main/kotlin/cc/rits/membership/console/paymaster/usecase/purchase_request/CreatePurchaseRequestUseCase.kt @@ -0,0 +1,55 @@ +package cc.rits.membership.console.paymaster.usecase.purchase_request + +import cc.rits.membership.console.paymaster.client.response.UserInfoResponse +import cc.rits.membership.console.paymaster.domain.model.PurchaseRequestModel +import cc.rits.membership.console.paymaster.domain.model.UserModel +import cc.rits.membership.console.paymaster.domain.repository.PurchaseRequestRepository +import cc.rits.membership.console.paymaster.enums.PurchaseRequestStatus +import cc.rits.membership.console.paymaster.enums.UserRole +import cc.rits.membership.console.paymaster.infrastructure.api.request.UpsertPurchaseRequestRequest +import io.micronaut.security.authentication.Authentication +import jakarta.inject.Singleton +import javax.transaction.Transactional + +/** + * 購入申請作成ユースケース + */ +@Singleton +@Transactional +@Suppress("UNCHECKED_CAST") +open class CreatePurchaseRequestUseCase( + private val purchaseRequestRepository: PurchaseRequestRepository +) { + /** + * 購入申請を作成 + * + * @param authentication 認証情報 + * @param requestBody 購入申請作成リクエスト + */ + open fun handle(authentication: Authentication, requestBody: UpsertPurchaseRequestRequest) { + val userInfo = authentication.attributes["userInfo"] as UserInfoResponse + val userModel = UserModel( + id = userInfo.id, + firstName = userInfo.firstName, + lastName = userInfo.lastName, + entranceYear = userInfo.entranceYear, + roles = userInfo.userGroups.flatMap { userGroup -> + userGroup.roles.mapNotNull { + UserRole.findById(it) + } + } + ) + + val purchaseRequestModel = PurchaseRequestModel( + name = requestBody.name, + description = requestBody.description, + price = requestBody.price, + quantity = requestBody.quantity, + url = requestBody.url, + status = PurchaseRequestStatus.PENDING_APPROVAL, + requestedBy = userModel + ) + + purchaseRequestRepository.insert(purchaseRequestModel) + } +} diff --git a/src/main/kotlin/cc/rits/membership/console/paymaster/util/ValidationUtil.kt b/src/main/kotlin/cc/rits/membership/console/paymaster/util/ValidationUtil.kt new file mode 100644 index 0000000..61a7f7b --- /dev/null +++ b/src/main/kotlin/cc/rits/membership/console/paymaster/util/ValidationUtil.kt @@ -0,0 +1,40 @@ +package cc.rits.membership.console.paymaster.util + +import io.micronaut.core.util.StringUtils + +/** + * バリデーションユーティリティ + */ +class ValidationUtil { + companion object { + /** + * 文字列の長さが範囲に収まるかチェック + * + * @param string 文字列 + * @param min 最小値 + * @param max 最大値 + * + * @return バリデーション結果 + */ + fun checkStringLength(string: String, min: Int, max: Int): Boolean { + if (StringUtils.isEmpty(string) && min != 0) { + return false + } + + return string.length in min..max + } + + /** + * 数値が範囲に収まるかチェック + * + * @param value 数値 + * @param min 最小値 + * @param max 最大値 + * + * @return バリデーション結果 + */ + fun checkNumberLength(value: Int, min: Int, max: Int): Boolean { + return value in min..max + } + } +} diff --git a/src/test/groovy/cc/rits/membership/console/paymaster/BaseSpec.groovy b/src/test/groovy/cc/rits/membership/console/paymaster/BaseSpec.groovy index 8f64a3b..0411916 100644 --- a/src/test/groovy/cc/rits/membership/console/paymaster/BaseSpec.groovy +++ b/src/test/groovy/cc/rits/membership/console/paymaster/BaseSpec.groovy @@ -6,7 +6,7 @@ import io.micronaut.test.extensions.spock.annotation.MicronautTest import jakarta.inject.Inject import spock.lang.Specification -@MicronautTest +@MicronautTest(transactional = false) abstract class BaseSpec extends Specification { @Inject diff --git a/src/test/groovy/cc/rits/membership/console/paymaster/infrastructure/api/controller/PurchaseRequestRestController_IT.groovy b/src/test/groovy/cc/rits/membership/console/paymaster/infrastructure/api/controller/PurchaseRequestRestController_IT.groovy index f797dae..d8eb19b 100644 --- a/src/test/groovy/cc/rits/membership/console/paymaster/infrastructure/api/controller/PurchaseRequestRestController_IT.groovy +++ b/src/test/groovy/cc/rits/membership/console/paymaster/infrastructure/api/controller/PurchaseRequestRestController_IT.groovy @@ -7,10 +7,12 @@ import cc.rits.membership.console.paymaster.client.response.UserInfoResponse import cc.rits.membership.console.paymaster.client.response.UserInfosResponse import cc.rits.membership.console.paymaster.enums.PurchaseRequestStatus import cc.rits.membership.console.paymaster.enums.UserRole +import cc.rits.membership.console.paymaster.exception.BadRequestException import cc.rits.membership.console.paymaster.exception.ErrorCode import cc.rits.membership.console.paymaster.exception.NotFoundException import cc.rits.membership.console.paymaster.exception.UnauthorizedException import cc.rits.membership.console.paymaster.helper.TableHelper +import cc.rits.membership.console.paymaster.infrastructure.api.request.UpsertPurchaseRequestRequest import cc.rits.membership.console.paymaster.infrastructure.api.response.PurchaseRequestResponse import cc.rits.membership.console.paymaster.infrastructure.api.response.PurchaseRequestsResponse import io.micronaut.http.HttpStatus @@ -20,6 +22,7 @@ import io.micronaut.test.annotation.MockBean import jakarta.inject.Inject import reactor.core.publisher.Mono import spock.lang.Shared +import spock.lang.Unroll /** * 購入申請APIの統合テスト @@ -27,8 +30,9 @@ import spock.lang.Shared class PurchaseRequestRestController_IT extends BaseRestController_IT { // API PATH static final BASE_PATH = "/api/purchase-requests" - static final GET_PURCHASE_REQUESTS_API_PATH = BASE_PATH + static final CREATE_PURCHASE_REQUEST_API_PATH = BASE_PATH static final GET_PURCHASE_REQUEST_API_PATH = BASE_PATH + "/%s" + static final GET_PURCHASE_REQUESTS_API_PATH = BASE_PATH @Inject IAMClient iamClient @@ -175,4 +179,60 @@ class PurchaseRequestRestController_IT extends BaseRestController_IT { final request = this.getRequest(String.format(GET_PURCHASE_REQUEST_API_PATH, UUID.randomUUID())) this.execute(request, new UnauthorizedException(ErrorCode.USER_NOT_LOGGED_IN)) } + + def "購入申請作成API: 正常系 購入申請を作成できる"() { + given: + final userInfoResponse = new UserInfoResponse( + 1, "test", "test", 2022, [UserRole.PAYMASTER_ADMIN.toString()], [ + new UserGroupResponse(1, "test", [UserRole.PAYMASTER_ADMIN.id]) + ]) + + final upsertPurchaseRequestRequest = new UpsertPurchaseRequestRequest("A", "description", 1000, 1, "url") + + final request = this.postRequest(CREATE_PURCHASE_REQUEST_API_PATH, upsertPurchaseRequestRequest) // + .header("X-Membership-Console-User", this.createAuthenticationInfo(userInfoResponse)) + + expect: + this.execute(request, HttpStatus.OK) + final result = sql.firstRow("SELECT * FROM purchase_request") + result.id != null + result.name == upsertPurchaseRequestRequest.name + result.description == upsertPurchaseRequestRequest.description + result.price == upsertPurchaseRequestRequest.price + result.quantity == upsertPurchaseRequestRequest.quantity + result.url == upsertPurchaseRequestRequest.url + result.status == PurchaseRequestStatus.PENDING_APPROVAL.id + result.requested_by == 1 + } + + @Unroll + def "購入申請作成API: 異常系 リクエストボディのバリデーション"() { + given: + final userInfoResponse = new UserInfoResponse( + 1, "test", "test", 2022, [UserRole.PAYMASTER_ADMIN.toString()], [ + new UserGroupResponse(1, "test", [UserRole.PAYMASTER_ADMIN.id]) + ]) + + final upsertPurchaseRequestRequest = new UpsertPurchaseRequestRequest(name, description, price, quantity, url) + + final request = this.postRequest(CREATE_PURCHASE_REQUEST_API_PATH, upsertPurchaseRequestRequest) // + .header("X-Membership-Console-User", this.createAuthenticationInfo(userInfoResponse)) + + expect: + this.execute(request, new BadRequestException(expectedErrorCode)) + + where: + name | description | price | quantity | url || expectedErrorCode + "A".repeat(500) | "description" | 100 | 1 | "url" || ErrorCode.INVALID_PURCHASE_REQUEST_NAME_LENGTH + "A" | "*".repeat(2000) | 100 | 1 | "url" || ErrorCode.INVALID_PURCHASE_REQUEST_DESCRIPTION_LENGTH + "A" | "description" | -1 | 1 | "url" || ErrorCode.INVALID_PURCHASE_REQUEST_PRICE + "A" | "description" | 100 | -1 | "url" || ErrorCode.INVALID_PURCHASE_REQUEST_QUANTITY + "A" | "description" | 100 | 1 | "*".repeat(2000) || ErrorCode.INVALID_PURCHASE_REQUEST_URL_LENGTH + } + + def "購入申請作成API: 異常系 ログインしていない場合は401エラー"() { + expect: + final request = this.getRequest(String.format(CREATE_PURCHASE_REQUEST_API_PATH, _)) + this.execute(request, new UnauthorizedException(ErrorCode.USER_NOT_LOGGED_IN)) + } } diff --git a/src/test/groovy/cc/rits/membership/console/paymaster/infrastructure/data/repository_impl/PurchaseRequestRepositoryImpl_UT.groovy b/src/test/groovy/cc/rits/membership/console/paymaster/infrastructure/data/repository_impl/PurchaseRequestRepositoryImpl_UT.groovy index 3988a8b..8fa53bc 100644 --- a/src/test/groovy/cc/rits/membership/console/paymaster/infrastructure/data/repository_impl/PurchaseRequestRepositoryImpl_UT.groovy +++ b/src/test/groovy/cc/rits/membership/console/paymaster/infrastructure/data/repository_impl/PurchaseRequestRepositoryImpl_UT.groovy @@ -5,6 +5,8 @@ import cc.rits.membership.console.paymaster.client.IAMClient import cc.rits.membership.console.paymaster.client.IAMClientImpl import cc.rits.membership.console.paymaster.client.response.UserGroupResponse import cc.rits.membership.console.paymaster.client.response.UserInfoResponse +import cc.rits.membership.console.paymaster.domain.model.PurchaseRequestModel +import cc.rits.membership.console.paymaster.domain.model.UserModel import cc.rits.membership.console.paymaster.domain.repository.PurchaseRequestRepository import cc.rits.membership.console.paymaster.enums.PurchaseRequestStatus import cc.rits.membership.console.paymaster.enums.UserRole @@ -17,6 +19,8 @@ import jakarta.inject.Inject import reactor.core.publisher.Mono import spock.lang.Shared +import java.time.LocalDateTime + /** * 購入申請リポジトリの単体テスト */ @@ -51,6 +55,28 @@ class PurchaseRequestRepositoryImpl_UT extends BaseDatabaseSpec { this.tokenResponse = new TokenResponse("", "") } + def "insert: 購入申請を登録できる"() { + given: + final userModel = new UserModel(1, "", "", 2022, [UserRole.PAYMASTER_ADMIN]) + final purchaseRequestModel = new PurchaseRequestModel( + UUID.randomUUID(), "", "", 1000, 1, "", PurchaseRequestStatus.PENDING_APPROVAL, userModel, LocalDateTime.now() + ) + + when: + this.sut.insert(purchaseRequestModel) + + then: + final result = sql.firstRow("SELECT * FROM purchase_request") + result.id == purchaseRequestModel.id + result.name == purchaseRequestModel.name + result.description == purchaseRequestModel.description + result.price == purchaseRequestModel.price + result.quantity == purchaseRequestModel.quantity + result.url == purchaseRequestModel.url + result.status == purchaseRequestModel.status.id + result.requested_by == purchaseRequestModel.requestedBy.id + } + def "findById: idから購入申請を取得できる"() { given: final expectedId = UUID.randomUUID() diff --git a/src/test/groovy/cc/rits/membership/console/paymaster/usecase/purchase_request/CreatePurchaseRequestUseCase_UT.groovy b/src/test/groovy/cc/rits/membership/console/paymaster/usecase/purchase_request/CreatePurchaseRequestUseCase_UT.groovy new file mode 100644 index 0000000..23106a2 --- /dev/null +++ b/src/test/groovy/cc/rits/membership/console/paymaster/usecase/purchase_request/CreatePurchaseRequestUseCase_UT.groovy @@ -0,0 +1,41 @@ +package cc.rits.membership.console.paymaster.usecase.purchase_request + +import cc.rits.membership.console.paymaster.BaseSpec +import cc.rits.membership.console.paymaster.client.response.UserInfoResponse +import cc.rits.membership.console.paymaster.domain.repository.PurchaseRequestRepository +import cc.rits.membership.console.paymaster.helper.RandomHelper +import cc.rits.membership.console.paymaster.infrastructure.api.request.UpsertPurchaseRequestRequest +import cc.rits.membership.console.paymaster.infrastructure.data.respository_impl.PurchaseRequestRepositoryImpl +import io.micronaut.security.authentication.Authentication +import io.micronaut.test.annotation.MockBean +import jakarta.inject.Inject + +/** + * 購入申請作成ユースケースの単体テスト + */ +class CreatePurchaseRequestUseCase_UT extends BaseSpec { + + @Inject + CreatePurchaseRequestUseCase sut + + @Inject + PurchaseRequestRepository purchaseRequestRepository + + @MockBean(PurchaseRequestRepositoryImpl) + PurchaseRequestRepository purchaseRequestRepository() { + return Mock(PurchaseRequestRepository) + } + + def "handle: 購入申請を作成できる"() { + given: + final authentication = Authentication.build("1", [], Map.of("userInfo", RandomHelper.mock(UserInfoResponse))) + final upsertPurchaseRequestRequest = RandomHelper.mock(UpsertPurchaseRequestRequest) + + when: + this.sut.handle(authentication, upsertPurchaseRequestRequest) + + then: + 1 * this.purchaseRequestRepository.insert(_) + noExceptionThrown() + } +} diff --git a/src/test/groovy/cc/rits/membership/console/paymaster/usecase/purchase_request/GetPurchaseRequestUseCase_UT.groovy b/src/test/groovy/cc/rits/membership/console/paymaster/usecase/purchase_request/GetPurchaseRequestUseCase_UT.groovy index 335d0bf..ecaa4ca 100644 --- a/src/test/groovy/cc/rits/membership/console/paymaster/usecase/purchase_request/GetPurchaseRequestUseCase_UT.groovy +++ b/src/test/groovy/cc/rits/membership/console/paymaster/usecase/purchase_request/GetPurchaseRequestUseCase_UT.groovy @@ -39,7 +39,7 @@ class GetPurchaseRequestUseCase_UT extends BaseSpec { result == purchaseRequestModel } - def "存在しない場合は404エラー"() { + def "handle: 存在しない場合は404エラー"() { given: final id = UUID.randomUUID() diff --git a/src/test/groovy/cc/rits/membership/console/paymaster/util/ValidationUtil_UT.groovy b/src/test/groovy/cc/rits/membership/console/paymaster/util/ValidationUtil_UT.groovy new file mode 100644 index 0000000..acbb822 --- /dev/null +++ b/src/test/groovy/cc/rits/membership/console/paymaster/util/ValidationUtil_UT.groovy @@ -0,0 +1,43 @@ +package cc.rits.membership.console.paymaster.util + +import cc.rits.membership.console.paymaster.BaseSpec +import cc.rits.membership.console.paymaster.helper.RandomHelper +import spock.lang.Unroll + +/** + * バリデーションユーティリティの単体テスト + */ +class ValidationUtil_UT extends BaseSpec { + + @Unroll + def "checkStringLength: 文字列の長さが範囲に収まるかチェックできる"() { + when: + final result = ValidationUtil.@Companion.checkStringLength(string, min, max) + + then: + result == expectedResult + + where: + string | min | max || expectedResult + "" | 1 | 10 || false + "" | 0 | 10 || true + RandomHelper.alphanumeric(3) | 1 | 10 || true + RandomHelper.alphanumeric(11) | 1 | 10 || false + } + + @Unroll + def "checkNumberLength: 数値が範囲に収まるかチェックできる"() { + when: + final result = ValidationUtil.@Companion.checkNumberLength(value, min, max) + + then: + result == expectedResult + + where: + value | min | max || expectedResult + 0 | 1 | 10 || false + 3 | 1 | 10 || true + 11 | 1 | 10 || false + } + +}