[#34] 회원 / 인증 도메인 재정의 #43

Merged
pricelees merged 73 commits from refactor/#34 into main 2025-09-13 10:13:45 +00:00
Showing only changes of commit 3bed383218 - Show all commits

View File

@ -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,162 +26,47 @@ 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("특정 날짜에 예약 가능한 테마 목록을 조회한다.") {
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("정상 응답") { test("정상 응답") {
val date = LocalDate.now().plusDays(1) val adminToken = authUtil.defaultAdminLogin()
for (i in 1..10) { for (i in 1..10) {
createDummySchedule( dummyInitializer.createSchedule(
createRequest.copy( adminToken = adminToken,
date = date, request = createRequest.copy(
time = LocalTime.now().plusMinutes(i.toLong()) date = date,
time = LocalTime.now().plusMinutes(i.toLong())
) )
) )
} }
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,26 +77,49 @@ 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,
date = date, request = createRequest.copy(
time = LocalTime.now().plusMinutes(i.toLong()), date = date,
themeId = createdSchedule.themeId time = LocalTime.now().plusMinutes(i.toLong()),
themeId = createdSchedule.themeId
) )
) )
} }
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()
createRequest.copy(date = LocalDate.now(), time = LocalTime.now().plusMinutes(1)) val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
adminToken = token,
request =
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")
}
} }