generated from pricelees/issue-pr-template
test: 일정(schedule) 테스트에 새로 추가된 회원 및 인증 권한 테스트 추가
This commit is contained in:
parent
ee9d8cd9f0
commit
3bed383218
@ -4,22 +4,17 @@ import io.kotest.matchers.date.shouldBeAfter
|
|||||||
import io.kotest.matchers.nulls.shouldNotBeNull
|
import io.kotest.matchers.nulls.shouldNotBeNull
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import io.kotest.matchers.shouldNotBe
|
import io.kotest.matchers.shouldNotBe
|
||||||
import io.restassured.module.kotlin.extensions.Extract
|
|
||||||
import io.restassured.module.kotlin.extensions.Given
|
|
||||||
import io.restassured.module.kotlin.extensions.When
|
|
||||||
import io.restassured.response.ValidatableResponse
|
|
||||||
import org.hamcrest.CoreMatchers.equalTo
|
import org.hamcrest.CoreMatchers.equalTo
|
||||||
import org.hamcrest.CoreMatchers.notNullValue
|
import org.hamcrest.CoreMatchers.notNullValue
|
||||||
import org.springframework.data.repository.findByIdOrNull
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
|
import org.springframework.http.HttpMethod
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.http.MediaType
|
import roomescape.admin.infrastructure.persistence.AdminPermissionLevel
|
||||||
import roomescape.auth.exception.AuthErrorCode
|
import roomescape.auth.exception.AuthErrorCode
|
||||||
import roomescape.member.infrastructure.persistence.Role
|
|
||||||
import roomescape.schedule.exception.ScheduleErrorCode
|
import roomescape.schedule.exception.ScheduleErrorCode
|
||||||
import roomescape.schedule.infrastructure.persistence.ScheduleEntity
|
import roomescape.schedule.infrastructure.persistence.ScheduleEntity
|
||||||
import roomescape.schedule.infrastructure.persistence.ScheduleRepository
|
import roomescape.schedule.infrastructure.persistence.ScheduleRepository
|
||||||
import roomescape.schedule.infrastructure.persistence.ScheduleStatus
|
import roomescape.schedule.infrastructure.persistence.ScheduleStatus
|
||||||
import roomescape.schedule.web.ScheduleCreateRequest
|
|
||||||
import roomescape.schedule.web.ScheduleUpdateRequest
|
import roomescape.schedule.web.ScheduleUpdateRequest
|
||||||
import roomescape.util.*
|
import roomescape.util.*
|
||||||
import roomescape.util.ScheduleFixture.createRequest
|
import roomescape.util.ScheduleFixture.createRequest
|
||||||
@ -31,152 +26,37 @@ class ScheduleApiTest(
|
|||||||
) : FunSpecSpringbootTest() {
|
) : FunSpecSpringbootTest() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
context("관리자가 아니면 접근할 수 없다.") {
|
|
||||||
lateinit var token: String
|
|
||||||
|
|
||||||
beforeTest {
|
|
||||||
token = authUtil.loginAsUser()
|
|
||||||
}
|
|
||||||
|
|
||||||
val commonAssertion: ValidatableResponse.() -> Unit = {
|
|
||||||
statusCode(HttpStatus.FORBIDDEN.value())
|
|
||||||
body(
|
|
||||||
"code",
|
|
||||||
equalTo(AuthErrorCode.ACCESS_DENIED.errorCode)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
test("일정 상세: GET /schedules/{id}") {
|
|
||||||
runTest(
|
|
||||||
token = token,
|
|
||||||
on = {
|
|
||||||
get("/schedules/$INVALID_PK")
|
|
||||||
},
|
|
||||||
expect = commonAssertion
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
test("일정 생성: POST /schedules") {
|
|
||||||
runTest(
|
|
||||||
token = token,
|
|
||||||
using = {
|
|
||||||
body(createRequest)
|
|
||||||
},
|
|
||||||
on = {
|
|
||||||
get("/schedules/$INVALID_PK")
|
|
||||||
},
|
|
||||||
expect = commonAssertion
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
test("일정 수정: PATCH /schedules/{id}") {
|
|
||||||
val createdSchedule: ScheduleEntity =
|
|
||||||
createDummySchedule(
|
|
||||||
createRequest
|
|
||||||
)
|
|
||||||
|
|
||||||
runTest(
|
|
||||||
token = token,
|
|
||||||
using = {
|
|
||||||
body(createRequest)
|
|
||||||
},
|
|
||||||
on = {
|
|
||||||
patch("/schedules/${createdSchedule.id}")
|
|
||||||
},
|
|
||||||
expect = commonAssertion
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
test("일정 삭제: DELETE /schedules/{id}") {
|
|
||||||
val createdSchedule: ScheduleEntity =
|
|
||||||
createDummySchedule(
|
|
||||||
createRequest
|
|
||||||
)
|
|
||||||
|
|
||||||
runTest(
|
|
||||||
token = token,
|
|
||||||
on = {
|
|
||||||
delete("/schedules/${createdSchedule.id}")
|
|
||||||
},
|
|
||||||
expect = commonAssertion
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context("일반 회원도 접근할 수 있다.") {
|
|
||||||
lateinit var token: String
|
|
||||||
|
|
||||||
beforeTest {
|
|
||||||
token = authUtil.loginAsUser()
|
|
||||||
}
|
|
||||||
|
|
||||||
test("예약 가능 테마 조회: GET /schedules/themes?date={date}") {
|
|
||||||
val date = LocalDate.now().plusDays(1)
|
|
||||||
val time = LocalTime.now()
|
|
||||||
val createdSchedule: ScheduleEntity =
|
|
||||||
createDummySchedule(
|
|
||||||
createRequest.copy(
|
|
||||||
date = date,
|
|
||||||
time = time
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
runTest(
|
|
||||||
token = token,
|
|
||||||
on = {
|
|
||||||
get("/schedules/themes?date=$date")
|
|
||||||
},
|
|
||||||
expect = {
|
|
||||||
statusCode(HttpStatus.OK.value())
|
|
||||||
body("data.themeIds.size()", equalTo(1))
|
|
||||||
body("data.themeIds[0]", equalTo(createdSchedule.themeId))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
test("동일한 날짜, 테마에 대한 시간 조회: GET /schedules?date={date}&themeId={themeId}") {
|
|
||||||
val date = LocalDate.now().plusDays(1)
|
|
||||||
val time = LocalTime.now()
|
|
||||||
|
|
||||||
val createdSchedule: ScheduleEntity =
|
|
||||||
createDummySchedule(
|
|
||||||
createRequest.copy(
|
|
||||||
date = date,
|
|
||||||
time = time
|
|
||||||
)
|
|
||||||
)
|
|
||||||
createDummySchedule(
|
|
||||||
createRequest.copy(
|
|
||||||
date = date.plusDays(1L),
|
|
||||||
time = time,
|
|
||||||
themeId = createdSchedule.themeId
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
runTest(
|
|
||||||
token = token,
|
|
||||||
on = {
|
|
||||||
get("/schedules?date=$date&themeId=${createdSchedule.themeId}")
|
|
||||||
},
|
|
||||||
expect = {
|
|
||||||
statusCode(HttpStatus.OK.value())
|
|
||||||
body("data.schedules.size()", equalTo(1))
|
|
||||||
body("data.schedules[0].id", equalTo(createdSchedule.id))
|
|
||||||
assertProperties(
|
|
||||||
props = setOf("id", "time", "status"),
|
|
||||||
propsNameIfList = "schedules"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context("특정 날짜에 예약 가능한 테마 목록을 조회한다.") {
|
context("특정 날짜에 예약 가능한 테마 목록을 조회한다.") {
|
||||||
test("정상 응답") {
|
|
||||||
val date = LocalDate.now().plusDays(1)
|
val date = LocalDate.now().plusDays(1)
|
||||||
|
val endpoint = "/schedules/themes?date=$date"
|
||||||
|
|
||||||
|
context("권한이 없으면 접근할 수 없다.") {
|
||||||
|
test("관리자") {
|
||||||
|
runExceptionTest(
|
||||||
|
token = authUtil.defaultAdminLogin(),
|
||||||
|
method = HttpMethod.GET,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("비회원") {
|
||||||
|
runExceptionTest(
|
||||||
|
method = HttpMethod.GET,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test("정상 응답") {
|
||||||
|
val adminToken = authUtil.defaultAdminLogin()
|
||||||
|
|
||||||
for (i in 1..10) {
|
for (i in 1..10) {
|
||||||
createDummySchedule(
|
dummyInitializer.createSchedule(
|
||||||
createRequest.copy(
|
adminToken = adminToken,
|
||||||
|
request = createRequest.copy(
|
||||||
date = date,
|
date = date,
|
||||||
time = LocalTime.now().plusMinutes(i.toLong())
|
time = LocalTime.now().plusMinutes(i.toLong())
|
||||||
)
|
)
|
||||||
@ -184,9 +64,9 @@ class ScheduleApiTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
runTest(
|
runTest(
|
||||||
token = authUtil.loginAsUser(),
|
token = authUtil.defaultUserLogin(),
|
||||||
on = {
|
on = {
|
||||||
get("/schedules/themes?date=$date")
|
get(endpoint)
|
||||||
},
|
},
|
||||||
expect = {
|
expect = {
|
||||||
statusCode(HttpStatus.OK.value())
|
statusCode(HttpStatus.OK.value())
|
||||||
@ -197,17 +77,40 @@ class ScheduleApiTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
context("동일한 날짜, 테마에 대한 모든 시간을 조회한다.") {
|
context("동일한 날짜, 테마에 대한 모든 시간을 조회한다.") {
|
||||||
|
context("권한이 없으면 접근할 수 없다.") {
|
||||||
|
val endpoint = "/schedules?date=2025-09-12&themeId=12345"
|
||||||
|
|
||||||
|
test("관리자") {
|
||||||
|
runExceptionTest(
|
||||||
|
token = authUtil.defaultAdminLogin(),
|
||||||
|
method = HttpMethod.GET,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("비회원") {
|
||||||
|
runExceptionTest(
|
||||||
|
method = HttpMethod.GET,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
test("정상 응답") {
|
test("정상 응답") {
|
||||||
val date = LocalDate.now().plusDays(1)
|
val date = LocalDate.now().plusDays(1)
|
||||||
val createdSchedule = createDummySchedule(
|
val adminToken = authUtil.defaultAdminLogin()
|
||||||
createRequest.copy(
|
val createdSchedule = dummyInitializer.createSchedule(
|
||||||
date = date,
|
adminToken = adminToken,
|
||||||
time = LocalTime.now()
|
request = createRequest.copy(date = date, time = LocalTime.now())
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for (i in 1..10) {
|
for (i in 1..10) {
|
||||||
createDummySchedule(
|
dummyInitializer.createSchedule(
|
||||||
createRequest.copy(
|
adminToken = adminToken,
|
||||||
|
request = createRequest.copy(
|
||||||
date = date,
|
date = date,
|
||||||
time = LocalTime.now().plusMinutes(i.toLong()),
|
time = LocalTime.now().plusMinutes(i.toLong()),
|
||||||
themeId = createdSchedule.themeId
|
themeId = createdSchedule.themeId
|
||||||
@ -216,7 +119,7 @@ class ScheduleApiTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
runTest(
|
runTest(
|
||||||
token = authUtil.loginAsUser(),
|
token = authUtil.defaultUserLogin(),
|
||||||
on = {
|
on = {
|
||||||
get("/schedules?date=$date&themeId=${createdSchedule.themeId}")
|
get("/schedules?date=$date&themeId=${createdSchedule.themeId}")
|
||||||
},
|
},
|
||||||
@ -233,11 +136,48 @@ class ScheduleApiTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
context("관리자 페이지에서 특정 일정의 감사 정보를 조회한다.") {
|
context("관리자 페이지에서 특정 일정의 감사 정보를 조회한다.") {
|
||||||
|
context("권한이 없으면 접근할 수 없다.") {
|
||||||
|
val endpoint = "/schedules/${INVALID_PK}"
|
||||||
|
|
||||||
|
test("비회원") {
|
||||||
|
runExceptionTest(
|
||||||
|
method = HttpMethod.GET,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("회원") {
|
||||||
|
runExceptionTest(
|
||||||
|
token = authUtil.defaultUserLogin(),
|
||||||
|
method = HttpMethod.GET,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("권한이 ${AdminPermissionLevel.READ_SUMMARY}인 관리자") {
|
||||||
|
val admin = AdminFixture.create(permissionLevel = AdminPermissionLevel.READ_SUMMARY)
|
||||||
|
|
||||||
|
runExceptionTest(
|
||||||
|
token = authUtil.adminLogin(admin),
|
||||||
|
method = HttpMethod.GET,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test("정상 응답") {
|
test("정상 응답") {
|
||||||
val createdSchedule = createDummySchedule(createRequest)
|
val token = authUtil.defaultAdminLogin()
|
||||||
|
|
||||||
|
val createdSchedule = dummyInitializer.createSchedule(
|
||||||
|
adminToken = token,
|
||||||
|
request = createRequest
|
||||||
|
)
|
||||||
|
|
||||||
runTest(
|
runTest(
|
||||||
token = authUtil.loginAsAdmin(),
|
token = token,
|
||||||
on = {
|
on = {
|
||||||
get("/schedules/${createdSchedule.id}")
|
get("/schedules/${createdSchedule.id}")
|
||||||
},
|
},
|
||||||
@ -253,49 +193,67 @@ class ScheduleApiTest(
|
|||||||
}
|
}
|
||||||
).also {
|
).also {
|
||||||
it.extract().path<String>("data.createdAt") shouldNotBeNull {}
|
it.extract().path<String>("data.createdAt") shouldNotBeNull {}
|
||||||
it.extract().path<String>("data.createdBy") shouldNotBeNull {}
|
it.extract().path<LinkedHashMap<String, Any>>("data.createdBy") shouldNotBeNull {}
|
||||||
it.extract().path<String>("data.createdAt") shouldNotBeNull {}
|
it.extract().path<String>("data.updatedAt") shouldNotBeNull {}
|
||||||
it.extract().path<String>("data.createdAt") shouldNotBeNull {}
|
it.extract().path<LinkedHashMap<String, Any>>("data.updatedBy") shouldNotBeNull {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("일정이 없으면 실패한다.") {
|
test("일정이 없으면 실패한다.") {
|
||||||
runTest(
|
runExceptionTest(
|
||||||
token = authUtil.loginAsAdmin(),
|
token = authUtil.defaultAdminLogin(),
|
||||||
on = {
|
method = HttpMethod.GET,
|
||||||
get("/schedules/$INVALID_PK")
|
endpoint = "/schedules/$INVALID_PK",
|
||||||
},
|
expectedErrorCode = ScheduleErrorCode.SCHEDULE_NOT_FOUND
|
||||||
expect = {
|
|
||||||
statusCode(HttpStatus.NOT_FOUND.value())
|
|
||||||
body(
|
|
||||||
"code",
|
|
||||||
equalTo(ScheduleErrorCode.SCHEDULE_NOT_FOUND.errorCode)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context("일정을 생성한다.") {
|
context("일정을 생성한다.") {
|
||||||
lateinit var token: String
|
context("권한이 없으면 접근할 수 없다.") {
|
||||||
|
val endpoint = "/schedules"
|
||||||
|
|
||||||
beforeTest {
|
test("비회원") {
|
||||||
token = authUtil.loginAsAdmin()
|
runExceptionTest(
|
||||||
|
method = HttpMethod.POST,
|
||||||
|
requestBody = createRequest,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("회원") {
|
||||||
|
runExceptionTest(
|
||||||
|
token = authUtil.defaultUserLogin(),
|
||||||
|
method = HttpMethod.POST,
|
||||||
|
requestBody = createRequest,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
listOf(AdminPermissionLevel.READ_SUMMARY, AdminPermissionLevel.READ_ALL).forEach {
|
||||||
|
test("권한이 ${it}인 관리자") {
|
||||||
|
val admin = AdminFixture.create(permissionLevel = it)
|
||||||
|
|
||||||
|
runExceptionTest(
|
||||||
|
token = authUtil.adminLogin(admin),
|
||||||
|
method = HttpMethod.POST,
|
||||||
|
requestBody = createRequest,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("정상 생성 및 감사 정보 확인") {
|
test("정상 생성 및 감사 정보 확인") {
|
||||||
/**
|
val token = authUtil.defaultAdminLogin()
|
||||||
* FK 제약조건 해소를 위한 테마 생성 API 호출 및 ID 획득
|
|
||||||
*/
|
val themeId: Long = dummyInitializer.createTheme(
|
||||||
val themeId: Long = Given {
|
adminToken = token,
|
||||||
contentType(MediaType.APPLICATION_JSON_VALUE)
|
request = ThemeFixture.createRequest.copy(name = "theme-${System.currentTimeMillis()}")
|
||||||
header("Authorization", "Bearer $token")
|
).id
|
||||||
body(ThemeFixture.createRequest.copy(name = "theme-${System.currentTimeMillis()}"))
|
|
||||||
} When {
|
|
||||||
post("/admin/themes")
|
|
||||||
} Extract {
|
|
||||||
path("data.id")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 생성 테스트
|
* 생성 테스트
|
||||||
@ -328,62 +286,70 @@ class ScheduleApiTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("이미 동일한 날짜, 시간, 테마인 일정이 있으면 실패한다.") {
|
test("이미 동일한 날짜, 시간, 테마인 일정이 있으면 실패한다.") {
|
||||||
|
val token = authUtil.defaultAdminLogin()
|
||||||
val date = LocalDate.now().plusDays(1)
|
val date = LocalDate.now().plusDays(1)
|
||||||
val time = LocalTime.of(10, 0)
|
val time = LocalTime.of(10, 0)
|
||||||
|
|
||||||
val alreadyCreated: ScheduleEntity = createDummySchedule(
|
val alreadyCreated: ScheduleEntity = dummyInitializer.createSchedule(
|
||||||
createRequest.copy(
|
adminToken = token,
|
||||||
date = date, time = time
|
request = createRequest.copy(date = date, time = time)
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
runTest(
|
val body = createRequest.copy(date = date, time = time, themeId = alreadyCreated.themeId)
|
||||||
|
|
||||||
|
runExceptionTest(
|
||||||
token = token,
|
token = token,
|
||||||
using = {
|
method = HttpMethod.POST,
|
||||||
body(
|
endpoint = "/schedules",
|
||||||
createRequest.copy(
|
requestBody = body,
|
||||||
date = date, time = time, themeId = alreadyCreated.themeId
|
expectedErrorCode = ScheduleErrorCode.SCHEDULE_ALREADY_EXISTS
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
on = {
|
|
||||||
post("/schedules")
|
|
||||||
},
|
|
||||||
expect = {
|
|
||||||
statusCode(HttpStatus.CONFLICT.value())
|
|
||||||
body("code", equalTo(ScheduleErrorCode.SCHEDULE_ALREADY_EXISTS.errorCode))
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("입력된 날짜 + 시간이 현재 시간 이전이면 실패한다.") {
|
test("입력된 날짜 + 시간이 현재 시간 이전이면 실패한다.") {
|
||||||
runTest(
|
val token = authUtil.defaultAdminLogin()
|
||||||
|
val body = createRequest.copy(LocalDate.now(), LocalTime.now().minusMinutes(1))
|
||||||
|
|
||||||
|
runExceptionTest(
|
||||||
token = token,
|
token = token,
|
||||||
using = {
|
method = HttpMethod.POST,
|
||||||
body(
|
endpoint = "/schedules",
|
||||||
createRequest.copy(
|
requestBody = body,
|
||||||
date = LocalDate.now(),
|
expectedErrorCode = ScheduleErrorCode.PAST_DATE_TIME
|
||||||
time = LocalTime.now().minusMinutes(1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
on = {
|
|
||||||
post("/schedules")
|
|
||||||
},
|
|
||||||
expect = {
|
|
||||||
statusCode(HttpStatus.BAD_REQUEST.value())
|
|
||||||
body("code", equalTo(ScheduleErrorCode.PAST_DATE_TIME.errorCode))
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context("일정을 잠시 Hold 상태로 변경하여 중복 예약을 방지한다.") {
|
context("일정을 잠시 Hold 상태로 변경하여 중복 예약을 방지한다.") {
|
||||||
|
context("권한이 없으면 접근할 수 없다.") {
|
||||||
|
val endpoint = "/schedules/${INVALID_PK}/hold"
|
||||||
|
|
||||||
|
test("비회원") {
|
||||||
|
runExceptionTest(
|
||||||
|
method = HttpMethod.PATCH,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("관리자") {
|
||||||
|
runExceptionTest(
|
||||||
|
token = authUtil.defaultAdminLogin(),
|
||||||
|
method = HttpMethod.PATCH,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test("해당 일정이 ${ScheduleStatus.AVAILABLE} 상태이면 정상 응답") {
|
test("해당 일정이 ${ScheduleStatus.AVAILABLE} 상태이면 정상 응답") {
|
||||||
val createdSchedule: ScheduleEntity = createDummySchedule(createRequest)
|
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||||
|
adminToken = authUtil.defaultAdminLogin(),
|
||||||
|
request = createRequest
|
||||||
|
)
|
||||||
|
|
||||||
runTest(
|
runTest(
|
||||||
token = authUtil.loginAsUser(),
|
token = authUtil.defaultUserLogin(),
|
||||||
on = {
|
on = {
|
||||||
patch("/schedules/${createdSchedule.id}/hold")
|
patch("/schedules/${createdSchedule.id}/hold")
|
||||||
},
|
},
|
||||||
@ -399,32 +365,31 @@ class ScheduleApiTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("예약이 없으면 실패한다.") {
|
test("예약이 없으면 실패한다.") {
|
||||||
runTest(
|
runExceptionTest(
|
||||||
token = authUtil.loginAsUser(),
|
token = authUtil.defaultUserLogin(),
|
||||||
on = {
|
method = HttpMethod.PATCH,
|
||||||
patch("/schedules/$INVALID_PK/hold")
|
endpoint = "/schedules/$INVALID_PK/hold",
|
||||||
},
|
expectedErrorCode = ScheduleErrorCode.SCHEDULE_NOT_FOUND
|
||||||
expect = {
|
|
||||||
statusCode(HttpStatus.NOT_FOUND.value())
|
|
||||||
body("code", equalTo(ScheduleErrorCode.SCHEDULE_NOT_FOUND.errorCode))
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("해당 일정이 ${ScheduleStatus.AVAILABLE} 상태가 아니면 실패한다.") {
|
test("해당 일정이 ${ScheduleStatus.AVAILABLE} 상태가 아니면 실패한다.") {
|
||||||
val createdSchedule: ScheduleEntity = createDummySchedule(createRequest)
|
val adminToken = authUtil.defaultAdminLogin()
|
||||||
|
|
||||||
|
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||||
|
adminToken = adminToken,
|
||||||
|
request = createRequest
|
||||||
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 테스트를 위해 수정 API를 호출하여 상태를 HOLD 상태로 변경
|
* 테스트를 위해 수정 API를 호출하여 상태를 HOLD 상태로 변경
|
||||||
* 생성 API에서는 일정 생성 시 AVAILABLE을 기본 상태로 지정하기 때문.
|
* 생성 API에서는 일정 생성 시 AVAILABLE을 기본 상태로 지정하기 때문.
|
||||||
*/
|
*/
|
||||||
runTest(
|
runTest(
|
||||||
token = authUtil.loginAsAdmin(),
|
token = adminToken,
|
||||||
using = {
|
using = {
|
||||||
body(
|
body(
|
||||||
ScheduleUpdateRequest(
|
ScheduleUpdateRequest(status = ScheduleStatus.HOLD)
|
||||||
status = ScheduleStatus.HOLD
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
on = {
|
on = {
|
||||||
@ -435,15 +400,11 @@ class ScheduleApiTest(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
runTest(
|
runExceptionTest(
|
||||||
token = authUtil.loginAsUser(),
|
token = authUtil.defaultUserLogin(),
|
||||||
on = {
|
method = HttpMethod.PATCH,
|
||||||
patch("/schedules/${createdSchedule.id}/hold")
|
endpoint = "/schedules/${createdSchedule.id}/hold",
|
||||||
},
|
expectedErrorCode = ScheduleErrorCode.SCHEDULE_NOT_AVAILABLE
|
||||||
expect = {
|
|
||||||
statusCode(HttpStatus.CONFLICT.value())
|
|
||||||
body("code", equalTo(ScheduleErrorCode.SCHEDULE_NOT_AVAILABLE.errorCode))
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -454,14 +415,55 @@ class ScheduleApiTest(
|
|||||||
status = ScheduleStatus.BLOCKED
|
status = ScheduleStatus.BLOCKED
|
||||||
)
|
)
|
||||||
|
|
||||||
|
context("권한이 없으면 접근할 수 없다.") {
|
||||||
|
val endpoint = "/schedules/${INVALID_PK}"
|
||||||
|
|
||||||
|
test("비회원") {
|
||||||
|
runExceptionTest(
|
||||||
|
method = HttpMethod.PATCH,
|
||||||
|
requestBody = updateRequest,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("회원") {
|
||||||
|
runExceptionTest(
|
||||||
|
token = authUtil.defaultUserLogin(),
|
||||||
|
method = HttpMethod.PATCH,
|
||||||
|
requestBody = updateRequest,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
listOf(AdminPermissionLevel.READ_SUMMARY, AdminPermissionLevel.READ_ALL).forEach {
|
||||||
|
test("권한이 ${it}인 관리자") {
|
||||||
|
val admin = AdminFixture.create(permissionLevel = it)
|
||||||
|
|
||||||
|
runExceptionTest(
|
||||||
|
token = authUtil.adminLogin(admin),
|
||||||
|
method = HttpMethod.PATCH,
|
||||||
|
requestBody = updateRequest,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test("정상 수정 및 감사 정보 변경 확인") {
|
test("정상 수정 및 감사 정보 변경 확인") {
|
||||||
val createdSchedule: ScheduleEntity = createDummySchedule(
|
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||||
createRequest.copy(
|
adminToken = authUtil.defaultAdminLogin(),
|
||||||
|
request = createRequest.copy(
|
||||||
date = LocalDate.now().plusDays(1),
|
date = LocalDate.now().plusDays(1),
|
||||||
time = LocalTime.now().plusMinutes(1),
|
time = LocalTime.now().plusMinutes(1),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val otherAdminToken = authUtil.login("admin1@admin.com", "admin1", Role.ADMIN)
|
|
||||||
|
val otherAdminToken = authUtil.adminLogin(
|
||||||
|
AdminFixture.create(account = "otherAdmin", phone = "01099999999")
|
||||||
|
)
|
||||||
|
|
||||||
runTest(
|
runTest(
|
||||||
token = otherAdminToken,
|
token = otherAdminToken,
|
||||||
@ -487,10 +489,15 @@ class ScheduleApiTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("입력값이 없으면 수정하지 않는다.") {
|
test("입력값이 없으면 수정하지 않는다.") {
|
||||||
val createdSchedule: ScheduleEntity = createDummySchedule(createRequest)
|
val token = authUtil.defaultAdminLogin()
|
||||||
|
|
||||||
|
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||||
|
adminToken = token,
|
||||||
|
request = createRequest
|
||||||
|
)
|
||||||
|
|
||||||
runTest(
|
runTest(
|
||||||
token = authUtil.loginAsAdmin(),
|
token = token,
|
||||||
using = {
|
using = {
|
||||||
body(ScheduleUpdateRequest())
|
body(ScheduleUpdateRequest())
|
||||||
},
|
},
|
||||||
@ -509,52 +516,78 @@ class ScheduleApiTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("일정이 없으면 실패한다.") {
|
test("일정이 없으면 실패한다.") {
|
||||||
runTest(
|
runExceptionTest(
|
||||||
token = authUtil.loginAsAdmin(),
|
token = authUtil.defaultAdminLogin(),
|
||||||
using = {
|
method = HttpMethod.PATCH,
|
||||||
body(updateRequest)
|
requestBody = updateRequest,
|
||||||
},
|
endpoint = "/schedules/${INVALID_PK}",
|
||||||
on = {
|
expectedErrorCode = ScheduleErrorCode.SCHEDULE_NOT_FOUND
|
||||||
patch("/schedules/$INVALID_PK")
|
|
||||||
},
|
|
||||||
expect = {
|
|
||||||
statusCode(HttpStatus.NOT_FOUND.value())
|
|
||||||
body("code", equalTo(ScheduleErrorCode.SCHEDULE_NOT_FOUND.errorCode))
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("입력된 날짜 + 시간이 현재 시간 이전이면 실패한다.") {
|
test("입력된 날짜 + 시간이 현재 시간 이전이면 실패한다.") {
|
||||||
val createdSchedule: ScheduleEntity = createDummySchedule(
|
val token = authUtil.defaultAdminLogin()
|
||||||
|
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||||
|
adminToken = token,
|
||||||
|
request =
|
||||||
|
|
||||||
createRequest.copy(date = LocalDate.now(), time = LocalTime.now().plusMinutes(1))
|
createRequest.copy(date = LocalDate.now(), time = LocalTime.now().plusMinutes(1))
|
||||||
)
|
)
|
||||||
|
|
||||||
runTest(
|
runExceptionTest(
|
||||||
token = authUtil.loginAsAdmin(),
|
token = token,
|
||||||
using = {
|
method = HttpMethod.PATCH,
|
||||||
body(
|
requestBody = updateRequest.copy(time = LocalTime.now().minusMinutes(1)),
|
||||||
updateRequest.copy(
|
endpoint = "/schedules/${createdSchedule.id}",
|
||||||
time = LocalTime.now().minusMinutes(1)
|
expectedErrorCode = ScheduleErrorCode.PAST_DATE_TIME
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
on = {
|
|
||||||
patch("/schedules/${createdSchedule.id}")
|
|
||||||
},
|
|
||||||
expect = {
|
|
||||||
statusCode(HttpStatus.BAD_REQUEST.value())
|
|
||||||
body("code", equalTo(ScheduleErrorCode.PAST_DATE_TIME.errorCode))
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context("일정을 삭제한다.") {
|
context("일정을 삭제한다.") {
|
||||||
|
context("권한이 없으면 접근할 수 없다.") {
|
||||||
|
val endpoint = "/schedules/${INVALID_PK}"
|
||||||
|
|
||||||
|
test("비회원") {
|
||||||
|
runExceptionTest(
|
||||||
|
method = HttpMethod.DELETE,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("회원") {
|
||||||
|
runExceptionTest(
|
||||||
|
token = authUtil.defaultUserLogin(),
|
||||||
|
method = HttpMethod.DELETE,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
listOf(AdminPermissionLevel.READ_SUMMARY, AdminPermissionLevel.READ_ALL).forEach {
|
||||||
|
test("권한이 ${it}인 관리자") {
|
||||||
|
val admin = AdminFixture.create(permissionLevel = it)
|
||||||
|
|
||||||
|
runExceptionTest(
|
||||||
|
token = authUtil.adminLogin(admin),
|
||||||
|
method = HttpMethod.DELETE,
|
||||||
|
endpoint = endpoint,
|
||||||
|
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test("정상 삭제") {
|
test("정상 삭제") {
|
||||||
val createdSchedule: ScheduleEntity = createDummySchedule(createRequest)
|
val token = authUtil.defaultAdminLogin()
|
||||||
|
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||||
|
adminToken = token,
|
||||||
|
request = createRequest
|
||||||
|
)
|
||||||
|
|
||||||
runTest(
|
runTest(
|
||||||
token = authUtil.loginAsAdmin(),
|
token = token,
|
||||||
on = {
|
on = {
|
||||||
delete("/schedules/${createdSchedule.id}")
|
delete("/schedules/${createdSchedule.id}")
|
||||||
},
|
},
|
||||||
@ -567,19 +600,22 @@ class ScheduleApiTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("예약 중이거나 예약이 완료된 일정이면 실패한다.") {
|
test("예약 중이거나 예약이 완료된 일정이면 실패한다.") {
|
||||||
val createdSchedule: ScheduleEntity = createDummySchedule(createRequest)
|
val token = authUtil.defaultAdminLogin()
|
||||||
|
|
||||||
|
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||||
|
adminToken = token,
|
||||||
|
request = createRequest
|
||||||
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 테스트를 위해 수정 API를 호출하여 상태를 예약 중 상태로 변경
|
* 테스트를 위해 수정 API를 호출하여 상태를 예약 중 상태로 변경
|
||||||
* 생성 API에서는 일정 생성 시 AVAILABLE을 기본 상태로 지정하기 때문.
|
* 생성 API에서는 일정 생성 시 AVAILABLE을 기본 상태로 지정하기 때문.
|
||||||
*/
|
*/
|
||||||
runTest(
|
runTest(
|
||||||
token = authUtil.loginAsAdmin(),
|
token = token,
|
||||||
using = {
|
using = {
|
||||||
body(
|
body(
|
||||||
ScheduleUpdateRequest(
|
ScheduleUpdateRequest(status = ScheduleStatus.RESERVED)
|
||||||
status = ScheduleStatus.RESERVED
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
on = {
|
on = {
|
||||||
@ -593,48 +629,13 @@ class ScheduleApiTest(
|
|||||||
/**
|
/**
|
||||||
* 삭제 테스트
|
* 삭제 테스트
|
||||||
*/
|
*/
|
||||||
runTest(
|
runExceptionTest(
|
||||||
token = authUtil.loginAsAdmin(),
|
token = token,
|
||||||
on = {
|
method = HttpMethod.DELETE,
|
||||||
delete("/schedules/${createdSchedule.id}")
|
endpoint = "/schedules/${createdSchedule.id}",
|
||||||
},
|
expectedErrorCode = ScheduleErrorCode.SCHEDULE_IN_USE
|
||||||
expect = {
|
|
||||||
statusCode(HttpStatus.CONFLICT.value())
|
|
||||||
body("code", equalTo(ScheduleErrorCode.SCHEDULE_IN_USE.errorCode))
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createDummySchedule(request: ScheduleCreateRequest): ScheduleEntity {
|
|
||||||
val token = authUtil.loginAsAdmin()
|
|
||||||
|
|
||||||
val themeId: Long = if (request.themeId > 1L) {
|
|
||||||
request.themeId
|
|
||||||
} else {
|
|
||||||
Given {
|
|
||||||
contentType(MediaType.APPLICATION_JSON_VALUE)
|
|
||||||
header("Authorization", "Bearer $token")
|
|
||||||
body(ThemeFixture.createRequest.copy(name = "theme-${System.currentTimeMillis()}"))
|
|
||||||
} When {
|
|
||||||
post("/admin/themes")
|
|
||||||
} Extract {
|
|
||||||
path("data.id")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val createdScheduleId: Long = Given {
|
|
||||||
contentType(MediaType.APPLICATION_JSON_VALUE)
|
|
||||||
header("Authorization", "Bearer $token")
|
|
||||||
body(request.copy(themeId = themeId))
|
|
||||||
} When {
|
|
||||||
post("/schedules")
|
|
||||||
} Extract {
|
|
||||||
path("data.id")
|
|
||||||
}
|
|
||||||
|
|
||||||
return scheduleRepository.findByIdOrNull(createdScheduleId)
|
|
||||||
?: throw RuntimeException("unreachable line")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user