generated from pricelees/issue-pr-template
[#44] 매장 기능 도입 #45
657
src/test/kotlin/roomescape/schedule/AdminScheduleApiTest.kt
Normal file
657
src/test/kotlin/roomescape/schedule/AdminScheduleApiTest.kt
Normal file
@ -0,0 +1,657 @@
|
||||
package roomescape.schedule
|
||||
|
||||
import io.kotest.assertions.assertSoftly
|
||||
import io.kotest.matchers.date.shouldBeBefore
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.http.HttpStatus
|
||||
import roomescape.admin.infrastructure.persistence.AdminPermissionLevel
|
||||
import roomescape.admin.infrastructure.persistence.AdminType
|
||||
import roomescape.auth.exception.AuthErrorCode
|
||||
import roomescape.common.dto.AuditConstant
|
||||
import roomescape.common.dto.OperatorInfo
|
||||
import roomescape.schedule.exception.ScheduleErrorCode
|
||||
import roomescape.schedule.infrastructure.persistence.ScheduleEntity
|
||||
import roomescape.schedule.infrastructure.persistence.ScheduleRepository
|
||||
import roomescape.schedule.infrastructure.persistence.ScheduleStatus
|
||||
import roomescape.schedule.web.AdminScheduleSummaryResponse
|
||||
import roomescape.schedule.web.ScheduleUpdateRequest
|
||||
import roomescape.store.infrastructure.persistence.StoreEntity
|
||||
import roomescape.supports.*
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalTime
|
||||
|
||||
class AdminScheduleApiTest(
|
||||
private var scheduleRepository: ScheduleRepository
|
||||
) : FunSpecSpringbootTest() {
|
||||
|
||||
init {
|
||||
context("날짜, 시간, 테마로 특정 매장의 일정을 검색한다.") {
|
||||
context("권한이 없으면 접근할 수 없다.") {
|
||||
test("비회원") {
|
||||
runExceptionTest(
|
||||
method = HttpMethod.GET,
|
||||
endpoint = "/admin/stores/${INVALID_PK}/schedules",
|
||||
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||
)
|
||||
}
|
||||
|
||||
test("회원") {
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.defaultUserLogin(),
|
||||
method = HttpMethod.GET,
|
||||
endpoint = "/admin/stores/${INVALID_PK}/schedules",
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
context("정상 응답") {
|
||||
lateinit var store: StoreEntity
|
||||
lateinit var schedules: List<ScheduleEntity>
|
||||
lateinit var token: String
|
||||
|
||||
beforeTest {
|
||||
val today = LocalDate.now()
|
||||
store = dummyInitializer.createStore()
|
||||
val admin = AdminFixture.createStoreAdmin(storeId = store.id)
|
||||
token = testAuthUtil.adminLogin(admin).second
|
||||
|
||||
schedules =
|
||||
initialize("${today}인 일정 2개와 다음날의 일정 1개를 추가하며, 시간순 정렬 확인을 위해 ${today}인 일정 2개는 시간 내림차순으로 추가한다.") {
|
||||
listOf(
|
||||
dummyInitializer.createSchedule(
|
||||
storeId = store.id,
|
||||
request = ScheduleFixture.createRequest.copy(
|
||||
date = today,
|
||||
time = LocalTime.now().plusHours(2)
|
||||
)
|
||||
),
|
||||
dummyInitializer.createSchedule(
|
||||
storeId = store.id,
|
||||
request = ScheduleFixture.createRequest.copy(
|
||||
date = today,
|
||||
time = LocalTime.now().plusHours(1)
|
||||
)
|
||||
),
|
||||
dummyInitializer.createSchedule(
|
||||
storeId = store.id,
|
||||
request = ScheduleFixture.createRequest.copy(
|
||||
date = today.plusDays(1),
|
||||
time = LocalTime.of(11, 0)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
test("날짜, 테마 미입력: 오늘 날짜의 전체 테마") {
|
||||
runTest(
|
||||
token = token,
|
||||
on = {
|
||||
get("/admin/stores/${store.id}/schedules")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
body("data.schedules.size()", equalTo(schedules.filter { it.date == LocalDate.now() }.size))
|
||||
assertProperties(
|
||||
props = setOf("id", "themeName", "startFrom", "endAt", "status"),
|
||||
propsNameIfList = "schedules"
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
test("날짜만 입력: 입력된 날짜의 전체 테마") {
|
||||
val date = schedules[0].date
|
||||
runTest(
|
||||
token = token,
|
||||
on = {
|
||||
get("/admin/stores/${store.id}/schedules?date=${date}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
body("data.schedules.size()", equalTo(schedules.filter { it.date == date }.size))
|
||||
assertProperties(
|
||||
props = setOf("id", "themeName", "startFrom", "endAt", "status"),
|
||||
propsNameIfList = "schedules"
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
test("테마만 입력: 오늘 날짜의 입력된 테마") {
|
||||
val themeId = schedules[0].themeId
|
||||
runTest(
|
||||
token = token,
|
||||
on = {
|
||||
get("/admin/stores/${store.id}/schedules?themeId=${themeId}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
body("data.schedules.size()", equalTo(schedules.filter { it.themeId == themeId }.size))
|
||||
assertProperties(
|
||||
props = setOf("id", "themeName", "startFrom", "endAt", "status"),
|
||||
propsNameIfList = "schedules"
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
test("날짜, 테마 모두 입력") {
|
||||
val date = schedules[0].date
|
||||
val themeId = schedules[0].themeId
|
||||
runTest(
|
||||
token = token,
|
||||
on = {
|
||||
get("/admin/stores/${store.id}/schedules?date=${date}&themeId=${themeId}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
body(
|
||||
"data.schedules.size()",
|
||||
equalTo(schedules.filter { it.date == date && it.themeId == themeId }.size)
|
||||
)
|
||||
assertProperties(
|
||||
props = setOf("id", "themeName", "startFrom", "endAt", "status"),
|
||||
propsNameIfList = "schedules"
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
test("결과는 시간 오름차순으로 정렬된다.") {
|
||||
runTest(
|
||||
token = token,
|
||||
on = {
|
||||
get("/admin/stores/${store.id}/schedules")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
}
|
||||
).also {
|
||||
val response: List<AdminScheduleSummaryResponse> =
|
||||
ResponseParser.parseListResponse(it.extract().path("data.schedules"))
|
||||
|
||||
for (i in 0..<(response.size - 1)) {
|
||||
response[i].startFrom shouldBeBefore response[i + 1].startFrom
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context("일정의 감사 정보를 확인한다.") {
|
||||
lateinit var store: StoreEntity
|
||||
|
||||
beforeTest {
|
||||
store = dummyInitializer.createStore()
|
||||
}
|
||||
|
||||
context("권한이 없으면 접근할 수 없다.") {
|
||||
test("비회원") {
|
||||
runExceptionTest(
|
||||
method = HttpMethod.GET,
|
||||
endpoint = "/admin/schedules/${INVALID_PK}/audits",
|
||||
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||
)
|
||||
}
|
||||
|
||||
test("회원") {
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.defaultUserLogin(),
|
||||
method = HttpMethod.GET,
|
||||
endpoint = "/admin/schedules/${INVALID_PK}/audits",
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
|
||||
test("권한이 ${AdminPermissionLevel.READ_SUMMARY} 인 관리자") {
|
||||
listOf(
|
||||
AdminFixture.createStoreAdmin(permissionLevel = AdminPermissionLevel.READ_SUMMARY),
|
||||
AdminFixture.createHqAdmin(permissionLevel = AdminPermissionLevel.READ_SUMMARY),
|
||||
).forEach {
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.adminLogin(it).second,
|
||||
method = HttpMethod.GET,
|
||||
endpoint = "/admin/schedules/${INVALID_PK}/audits",
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("정상 응답") {
|
||||
val (admin, scheduleId) = initialize("감사 이력을 남기기 위해, 로그인 후 일정을 생성한다.") {
|
||||
val admin = AdminFixture.createStoreAdmin(storeId = store.id)
|
||||
|
||||
val themeId = initialize("일정 생성에 필요한 테마를 생성한다.") {
|
||||
dummyInitializer.createTheme(ThemeFixture.createRequest).id
|
||||
}
|
||||
|
||||
val scheduleId: Long = runTest(
|
||||
token = testAuthUtil.adminLogin(admin).second,
|
||||
using = {
|
||||
body(ScheduleFixture.createRequest.copy(themeId = themeId))
|
||||
},
|
||||
on = {
|
||||
post("/admin/stores/${store.id}/schedules")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
}
|
||||
).extract().path("data.id")
|
||||
|
||||
admin to scheduleId
|
||||
}
|
||||
|
||||
|
||||
runTest(
|
||||
token = testAuthUtil.adminLogin(admin).second,
|
||||
on = {
|
||||
get("/admin/schedules/${scheduleId}/audits")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
body("data.createdBy.id", equalTo(admin.id))
|
||||
body("data.updatedBy.id", equalTo(admin.id))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
test("감사 정보가 없으면 Unknown을 반환한다.") {
|
||||
val schedule: ScheduleEntity = initialize("감사 이력을 남기지 않기 위해, 로그인 없이 일정을 생성한다.") {
|
||||
dummyInitializer.createSchedule(storeId = store.id, request = ScheduleFixture.createRequest)
|
||||
}
|
||||
val unknownOperator: OperatorInfo = AuditConstant.UNKNOWN_OPERATOR
|
||||
|
||||
runTest(
|
||||
token = testAuthUtil.defaultHqAdminLogin().second,
|
||||
on = {
|
||||
get("/admin/schedules/${schedule.id}/audits")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
body("data.createdBy.id", equalTo(unknownOperator.id.toInt()))
|
||||
body("data.createdBy.name", equalTo(unknownOperator.name))
|
||||
body("data.updatedBy.id", equalTo(unknownOperator.id.toInt()))
|
||||
body("data.updatedBy.name", equalTo(unknownOperator.name))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
context("일정을 생성한다.") {
|
||||
context("권한이 없으면 접근할 수 없다.") {
|
||||
test("비회원") {
|
||||
runExceptionTest(
|
||||
method = HttpMethod.POST,
|
||||
endpoint = "/admin/stores/${INVALID_PK}/schedules",
|
||||
requestBody = ScheduleFixture.createRequest,
|
||||
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||
)
|
||||
}
|
||||
|
||||
test("회원") {
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.defaultUserLogin(),
|
||||
method = HttpMethod.POST,
|
||||
endpoint = "/admin/stores/${INVALID_PK}/schedules",
|
||||
requestBody = ScheduleFixture.createRequest,
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
|
||||
context("관리자") {
|
||||
listOf(
|
||||
AdminPermissionLevel.READ_SUMMARY, AdminPermissionLevel.READ_ALL
|
||||
).forEach {
|
||||
test("type: ${AdminType.STORE} / permission: $it") {
|
||||
val admin = AdminFixture.createStoreAdmin(permissionLevel = it)
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.adminLogin(admin).second,
|
||||
method = HttpMethod.POST,
|
||||
endpoint = "/admin/stores/${INVALID_PK}/schedules",
|
||||
requestBody = ScheduleFixture.createRequest,
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
AdminPermissionLevel.entries.forEach {
|
||||
test("type: ${AdminType.HQ} / permission: $it") {
|
||||
val admin = AdminFixture.createHqAdmin(permissionLevel = it)
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.adminLogin(admin).second,
|
||||
method = HttpMethod.POST,
|
||||
endpoint = "/admin/stores/${INVALID_PK}/schedules",
|
||||
requestBody = ScheduleFixture.createRequest,
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("정상 응답") {
|
||||
val (admin, token) = testAuthUtil.defaultStoreAdminLogin()
|
||||
val theme = dummyInitializer.createTheme()
|
||||
val request = ScheduleFixture.createRequest.copy(themeId = theme.id)
|
||||
|
||||
runTest(
|
||||
token = token,
|
||||
using = {
|
||||
body(request)
|
||||
},
|
||||
on = {
|
||||
post("/admin/stores/${admin.storeId}/schedules")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
}
|
||||
).also {
|
||||
assertSoftly(scheduleRepository.findByIdOrNull(it.extract().path("data.id"))!!) {
|
||||
this.createdBy shouldBe admin.id
|
||||
this.updatedBy shouldBe admin.id
|
||||
this.storeId shouldBe admin.storeId
|
||||
this.themeId shouldBe theme.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("날짜, 시간, 테마가 동일한 일정이 있으면 실패한다.") {
|
||||
val (admin, token) = testAuthUtil.defaultStoreAdminLogin()
|
||||
|
||||
val schedule = initialize("중복 테스트를 위한 사전 저장") {
|
||||
dummyInitializer.createSchedule(storeId = admin.storeId!!)
|
||||
}
|
||||
|
||||
val request = ScheduleFixture.createRequest.copy(
|
||||
date = schedule.date,
|
||||
time = schedule.time,
|
||||
themeId = schedule.themeId
|
||||
)
|
||||
|
||||
runExceptionTest(
|
||||
token = token,
|
||||
method = HttpMethod.POST,
|
||||
endpoint = "/admin/stores/${admin.storeId}/schedules",
|
||||
requestBody = request,
|
||||
expectedErrorCode = ScheduleErrorCode.SCHEDULE_ALREADY_EXISTS
|
||||
)
|
||||
}
|
||||
|
||||
test("과거 시간을 선택하면 실패한다.") {
|
||||
val (admin, token) = testAuthUtil.defaultStoreAdminLogin()
|
||||
val date = LocalDate.now()
|
||||
val time = LocalTime.now().minusMinutes(1)
|
||||
val theme = dummyInitializer.createTheme()
|
||||
|
||||
val request = ScheduleFixture.createRequest.copy(date, time, theme.id)
|
||||
|
||||
runExceptionTest(
|
||||
token = token,
|
||||
method = HttpMethod.POST,
|
||||
endpoint = "/admin/stores/${admin.storeId}/schedules",
|
||||
requestBody = request,
|
||||
expectedErrorCode = ScheduleErrorCode.PAST_DATE_TIME
|
||||
)
|
||||
}
|
||||
|
||||
test("겹치는 시간이 있으면 실패한다.") {
|
||||
val (admin, token) = testAuthUtil.defaultStoreAdminLogin()
|
||||
val tomorrow = LocalDate.now().plusDays(1)
|
||||
val theme = dummyInitializer.createTheme(
|
||||
ThemeFixture.createRequest.copy(availableMinutes = 100)
|
||||
)
|
||||
|
||||
initialize("내일 14:00 ~ 15:40인 일정 생성") {
|
||||
dummyInitializer.createSchedule(
|
||||
storeId = admin.storeId!!,
|
||||
request = ScheduleFixture.createRequest.copy(
|
||||
tomorrow,
|
||||
LocalTime.of(14, 0),
|
||||
theme.id
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val request = initialize("내일 14:30에 시작하는 요청 객체") {
|
||||
ScheduleFixture.createRequest.copy(
|
||||
tomorrow,
|
||||
LocalTime.of(14, 30),
|
||||
theme.id
|
||||
)
|
||||
}
|
||||
|
||||
runExceptionTest(
|
||||
token = token,
|
||||
method = HttpMethod.POST,
|
||||
endpoint = "/admin/stores/${admin.storeId}/schedules",
|
||||
requestBody = request,
|
||||
expectedErrorCode = ScheduleErrorCode.SCHEDULE_TIME_CONFLICT
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
context("일정을 수정한다.") {
|
||||
context("권한이 없으면 접근할 수 없다.") {
|
||||
test("비회원") {
|
||||
runExceptionTest(
|
||||
method = HttpMethod.PATCH,
|
||||
endpoint = "/admin/schedules/${INVALID_PK}",
|
||||
requestBody = ScheduleUpdateRequest(),
|
||||
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||
)
|
||||
}
|
||||
|
||||
test("회원") {
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.defaultUserLogin(),
|
||||
method = HttpMethod.PATCH,
|
||||
endpoint = "/admin/schedules/${INVALID_PK}",
|
||||
requestBody = ScheduleUpdateRequest(),
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
|
||||
context("관리자") {
|
||||
listOf(
|
||||
AdminPermissionLevel.READ_SUMMARY, AdminPermissionLevel.READ_ALL
|
||||
).forEach {
|
||||
test("type: ${AdminType.STORE} / permission: $it") {
|
||||
val admin = AdminFixture.createStoreAdmin(permissionLevel = it)
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.adminLogin(admin).second,
|
||||
method = HttpMethod.PATCH,
|
||||
endpoint = "/admin/schedules/${INVALID_PK}",
|
||||
requestBody = ScheduleUpdateRequest(),
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
AdminPermissionLevel.entries.forEach {
|
||||
test("type: ${AdminType.HQ} / permission: $it") {
|
||||
val admin = AdminFixture.createHqAdmin(permissionLevel = it)
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.adminLogin(admin).second,
|
||||
method = HttpMethod.PATCH,
|
||||
endpoint = "/admin/schedules/${INVALID_PK}",
|
||||
requestBody = ScheduleUpdateRequest(),
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context("정상 응답") {
|
||||
test("시간만 변경한다.") {
|
||||
val (admin, token) = testAuthUtil.defaultStoreAdminLogin()
|
||||
val schedule = initialize("수정을 위한 일정 생성") {
|
||||
dummyInitializer.createSchedule()
|
||||
}
|
||||
val updateTime = schedule.time.plusHours(1)
|
||||
|
||||
runTest(
|
||||
token = token,
|
||||
using = {
|
||||
body(ScheduleUpdateRequest(time = updateTime))
|
||||
},
|
||||
on = {
|
||||
patch("/admin/schedules/${schedule.id}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
}
|
||||
).also {
|
||||
val updated = scheduleRepository.findByIdOrNull(schedule.id)!!
|
||||
updated.time shouldBe updateTime
|
||||
updated.status shouldBe schedule.status
|
||||
updated.updatedAt shouldNotBe schedule.updatedAt
|
||||
}
|
||||
}
|
||||
|
||||
test("상태만 변경한다.") {
|
||||
val (admin, token) = testAuthUtil.defaultStoreAdminLogin()
|
||||
val schedule = initialize("수정을 위한 일정 생성") {
|
||||
dummyInitializer.createSchedule()
|
||||
}
|
||||
val updateStatus = ScheduleStatus.RESERVED
|
||||
|
||||
runTest(
|
||||
token = token,
|
||||
using = {
|
||||
body(ScheduleUpdateRequest(status = updateStatus))
|
||||
},
|
||||
on = {
|
||||
patch("/admin/schedules/${schedule.id}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
}
|
||||
).also {
|
||||
val updated = scheduleRepository.findByIdOrNull(schedule.id)!!
|
||||
updated.time shouldBe schedule.time
|
||||
updated.status shouldBe updateStatus
|
||||
updated.updatedAt shouldNotBe schedule.updatedAt
|
||||
}
|
||||
}
|
||||
|
||||
test("아무 값도 입력하지 않으면 바뀌지 않는다.") {
|
||||
val (admin, token) = testAuthUtil.defaultStoreAdminLogin()
|
||||
val schedule = initialize("수정을 위한 일정 생성") {
|
||||
dummyInitializer.createSchedule()
|
||||
}
|
||||
|
||||
runTest(
|
||||
token = token,
|
||||
using = {
|
||||
body(ScheduleUpdateRequest())
|
||||
},
|
||||
on = {
|
||||
patch("/admin/schedules/${schedule.id}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
}
|
||||
).also {
|
||||
val updated = scheduleRepository.findByIdOrNull(schedule.id)!!
|
||||
updated.time shouldBe schedule.time
|
||||
updated.status shouldBe schedule.status
|
||||
updated.updatedAt shouldBe schedule.updatedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context("일정을 삭제한다.") {
|
||||
context("권한이 없으면 접근할 수 없다.") {
|
||||
test("비회원") {
|
||||
runExceptionTest(
|
||||
method = HttpMethod.DELETE,
|
||||
endpoint = "/admin/schedules/${INVALID_PK}",
|
||||
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||
)
|
||||
}
|
||||
|
||||
test("회원") {
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.defaultUserLogin(),
|
||||
method = HttpMethod.DELETE,
|
||||
endpoint = "/admin/schedules/${INVALID_PK}",
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
|
||||
context("관리자") {
|
||||
listOf(
|
||||
AdminPermissionLevel.READ_SUMMARY, AdminPermissionLevel.READ_ALL
|
||||
).forEach {
|
||||
test("type: ${AdminType.STORE} / permission: $it") {
|
||||
val admin = AdminFixture.createStoreAdmin(permissionLevel = it)
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.adminLogin(admin).second,
|
||||
method = HttpMethod.DELETE,
|
||||
endpoint = "/admin/schedules/${INVALID_PK}",
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
AdminPermissionLevel.entries.forEach {
|
||||
test("type: ${AdminType.HQ} / permission: $it") {
|
||||
val admin = AdminFixture.createHqAdmin(permissionLevel = it)
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.adminLogin(admin).second,
|
||||
method = HttpMethod.DELETE,
|
||||
endpoint = "/admin/schedules/${INVALID_PK}",
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("정상 응답") {
|
||||
val (admin, token) = testAuthUtil.defaultStoreAdminLogin()
|
||||
val schedule = initialize("삭제를 위한 일정 생성") {
|
||||
dummyInitializer.createSchedule(storeId = admin.storeId!!)
|
||||
}
|
||||
|
||||
runTest(
|
||||
token = token,
|
||||
on = {
|
||||
delete("/admin/schedules/${schedule.id}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.NO_CONTENT.value())
|
||||
}
|
||||
).also {
|
||||
scheduleRepository.findByIdOrNull(schedule.id) shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
(ScheduleStatus.entries - listOf(ScheduleStatus.AVAILABLE, ScheduleStatus.BLOCKED)).forEach {
|
||||
test("상태가 ${it}인 일정은 삭제할 수 없다.") {
|
||||
val (admin, token) = testAuthUtil.defaultStoreAdminLogin()
|
||||
val schedule = initialize("삭제를 위한 일정 생성") {
|
||||
dummyInitializer.createSchedule(storeId = admin.storeId!!, status = it)
|
||||
}
|
||||
|
||||
runExceptionTest(
|
||||
token = token,
|
||||
method = HttpMethod.DELETE,
|
||||
endpoint = "/admin/schedules/${schedule.id}",
|
||||
expectedErrorCode = ScheduleErrorCode.SCHEDULE_IN_USE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,93 +1,50 @@
|
||||
package roomescape.schedule
|
||||
|
||||
import io.kotest.matchers.date.shouldBeAfter
|
||||
import io.kotest.matchers.nulls.shouldNotBeNull
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.CoreMatchers.notNullValue
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.http.HttpStatus
|
||||
import roomescape.admin.infrastructure.persistence.AdminPermissionLevel
|
||||
import roomescape.admin.infrastructure.persistence.AdminType
|
||||
import roomescape.auth.exception.AuthErrorCode
|
||||
import roomescape.schedule.exception.ScheduleErrorCode
|
||||
import roomescape.schedule.infrastructure.persistence.ScheduleEntity
|
||||
import roomescape.schedule.infrastructure.persistence.ScheduleRepository
|
||||
import roomescape.schedule.infrastructure.persistence.ScheduleStatus
|
||||
import roomescape.schedule.web.ScheduleUpdateRequest
|
||||
import roomescape.supports.*
|
||||
import roomescape.supports.ScheduleFixture.createRequest
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalTime
|
||||
|
||||
class ScheduleApiTest(
|
||||
private val scheduleRepository: ScheduleRepository
|
||||
) : FunSpecSpringbootTest() {
|
||||
|
||||
init {
|
||||
|
||||
context("특정 날짜에 예약 가능한 테마 목록을 조회한다.") {
|
||||
val date = LocalDate.now().plusDays(1)
|
||||
val endpoint = "/schedules/themes?date=$date"
|
||||
|
||||
context("특정 매장 + 날짜의 일정 및 테마 정보를 조회한다.") {
|
||||
test("정상 응답") {
|
||||
val adminToken = testAuthUtil.defaultHqAdminLogin()
|
||||
|
||||
for (i in 1..10) {
|
||||
val size = 2
|
||||
val date = LocalDate.now().plusDays(1)
|
||||
val store = dummyInitializer.createStore()
|
||||
initialize("조회를 위한 같은 날짜의 ${size}개의 일정 생성") {
|
||||
for (i in 1..size) {
|
||||
dummyInitializer.createSchedule(
|
||||
adminToken = adminToken,
|
||||
request = createRequest.copy(
|
||||
storeId = store.id,
|
||||
request = ScheduleFixture.createRequest.copy(
|
||||
date = date,
|
||||
time = LocalTime.now().plusMinutes(i.toLong())
|
||||
time = LocalTime.now().plusHours(i.toLong())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
runTest(
|
||||
token = testAuthUtil.defaultUserLogin(),
|
||||
on = {
|
||||
get(endpoint)
|
||||
get("/stores/${store.id}/schedules?date=${date}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
body("data.themeIds.size()", equalTo(10))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
context("동일한 날짜, 테마에 대한 모든 시간을 조회한다.") {
|
||||
|
||||
test("정상 응답") {
|
||||
val date = LocalDate.now().plusDays(1)
|
||||
val adminToken = testAuthUtil.defaultHqAdminLogin()
|
||||
val createdSchedule = dummyInitializer.createSchedule(
|
||||
adminToken = adminToken,
|
||||
request = createRequest.copy(date = date, time = LocalTime.now())
|
||||
)
|
||||
|
||||
for (i in 1..10) {
|
||||
dummyInitializer.createSchedule(
|
||||
adminToken = adminToken,
|
||||
request = createRequest.copy(
|
||||
date = date,
|
||||
time = LocalTime.now().plusMinutes(i.toLong()),
|
||||
themeId = createdSchedule.themeId
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
runTest(
|
||||
token = testAuthUtil.defaultUserLogin(),
|
||||
on = {
|
||||
get("/schedules?date=$date&themeId=${createdSchedule.themeId}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
body("data.schedules.size()", equalTo(11))
|
||||
body("data.schedules.size()", equalTo(size))
|
||||
assertProperties(
|
||||
props = setOf("id", "time", "status"),
|
||||
props = setOf("id", "startFrom", "endAt", "themeId", "themeName", "themeDifficulty", "status"),
|
||||
propsNameIfList = "schedules"
|
||||
)
|
||||
}
|
||||
@ -95,506 +52,70 @@ class ScheduleApiTest(
|
||||
}
|
||||
}
|
||||
|
||||
context("관리자 페이지에서 특정 일정의 감사 정보를 조회한다.") {
|
||||
context("일정을 ${ScheduleStatus.HOLD} 상태로 변경한다.") {
|
||||
context("권한이 없으면 접근할 수 없다.") {
|
||||
val endpoint = "/schedules/${INVALID_PK}"
|
||||
|
||||
test("비회원") {
|
||||
runExceptionTest(
|
||||
method = HttpMethod.GET,
|
||||
endpoint = endpoint,
|
||||
method = HttpMethod.POST,
|
||||
endpoint = "/schedules/${INVALID_PK}/hold",
|
||||
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||
)
|
||||
}
|
||||
|
||||
test("회원") {
|
||||
context("관리자") {
|
||||
AdminPermissionLevel.entries.flatMap { permission ->
|
||||
listOf(
|
||||
AdminType.STORE to permission,
|
||||
AdminType.HQ to permission,
|
||||
)
|
||||
}.forEach { (type, permission) ->
|
||||
val admin = AdminFixture.create(
|
||||
type = type,
|
||||
permissionLevel = permission
|
||||
)
|
||||
|
||||
test("type=${type} / permission=${permission}") {
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.defaultUserLogin(),
|
||||
method = HttpMethod.GET,
|
||||
endpoint = endpoint,
|
||||
token = testAuthUtil.adminLogin(admin).second,
|
||||
method = HttpMethod.POST,
|
||||
endpoint = "/schedules/${INVALID_PK}/hold",
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
|
||||
test("권한이 ${AdminPermissionLevel.READ_SUMMARY}인 관리자") {
|
||||
val admin = AdminFixture.create(permissionLevel = AdminPermissionLevel.READ_SUMMARY)
|
||||
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.adminLogin(admin),
|
||||
method = HttpMethod.GET,
|
||||
endpoint = endpoint,
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("정상 응답") {
|
||||
val token = testAuthUtil.defaultHqAdminLogin()
|
||||
|
||||
val createdSchedule = dummyInitializer.createSchedule(
|
||||
adminToken = token,
|
||||
request = createRequest
|
||||
)
|
||||
|
||||
runTest(
|
||||
token = token,
|
||||
on = {
|
||||
get("/schedules/${createdSchedule.id}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
body("data.id", equalTo(createdSchedule.id))
|
||||
assertProperties(
|
||||
props = setOf(
|
||||
"id", "date", "time", "status",
|
||||
"createdAt", "createdBy", "updatedAt", "updatedBy",
|
||||
)
|
||||
)
|
||||
}
|
||||
).also {
|
||||
it.extract().path<String>("data.createdAt") shouldNotBeNull {}
|
||||
it.extract().path<LinkedHashMap<String, Any>>("data.createdBy") shouldNotBeNull {}
|
||||
it.extract().path<String>("data.updatedAt") shouldNotBeNull {}
|
||||
it.extract().path<LinkedHashMap<String, Any>>("data.updatedBy") shouldNotBeNull {}
|
||||
}
|
||||
}
|
||||
|
||||
test("일정이 없으면 실패한다.") {
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.defaultHqAdminLogin(),
|
||||
method = HttpMethod.GET,
|
||||
endpoint = "/schedules/$INVALID_PK",
|
||||
expectedErrorCode = ScheduleErrorCode.SCHEDULE_NOT_FOUND
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
context("일정을 생성한다.") {
|
||||
context("권한이 없으면 접근할 수 없다.") {
|
||||
val endpoint = "/schedules"
|
||||
|
||||
test("비회원") {
|
||||
runExceptionTest(
|
||||
method = HttpMethod.POST,
|
||||
requestBody = createRequest,
|
||||
endpoint = endpoint,
|
||||
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||
)
|
||||
}
|
||||
|
||||
test("회원") {
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.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 = testAuthUtil.adminLogin(admin),
|
||||
method = HttpMethod.POST,
|
||||
requestBody = createRequest,
|
||||
endpoint = endpoint,
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("정상 생성 및 감사 정보 확인") {
|
||||
val token = testAuthUtil.defaultHqAdminLogin()
|
||||
|
||||
val themeId: Long = dummyInitializer.createTheme(
|
||||
adminToken = token,
|
||||
request = ThemeFixture.createRequest.copy(name = "theme-${System.currentTimeMillis()}")
|
||||
).id
|
||||
|
||||
/**
|
||||
* 생성 테스트
|
||||
*/
|
||||
runTest(
|
||||
token = token,
|
||||
using = {
|
||||
body(createRequest.copy(themeId = themeId))
|
||||
},
|
||||
on = {
|
||||
post("/schedules")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
body("data.id", notNullValue())
|
||||
}
|
||||
).also {
|
||||
val createdScheduleId: Long = it.extract().path("data.id")
|
||||
val createdSchedule: ScheduleEntity = scheduleRepository.findByIdOrNull(createdScheduleId)
|
||||
?: throw AssertionError("Unexpected Exception Occurred.")
|
||||
|
||||
createdSchedule.date shouldBe createRequest.date
|
||||
createdSchedule.time.hour shouldBe createRequest.time.hour
|
||||
createdSchedule.time.minute shouldBe createRequest.time.minute
|
||||
createdSchedule.createdAt shouldNotBeNull {}
|
||||
createdSchedule.createdBy shouldNotBeNull {}
|
||||
createdSchedule.updatedAt shouldNotBeNull {}
|
||||
createdSchedule.updatedBy shouldNotBeNull {}
|
||||
}
|
||||
}
|
||||
|
||||
test("이미 동일한 날짜, 시간, 테마인 일정이 있으면 실패한다.") {
|
||||
val token = testAuthUtil.defaultHqAdminLogin()
|
||||
val date = LocalDate.now().plusDays(1)
|
||||
val time = LocalTime.of(10, 0)
|
||||
|
||||
val alreadyCreated: ScheduleEntity = dummyInitializer.createSchedule(
|
||||
adminToken = token,
|
||||
request = createRequest.copy(date = date, time = time)
|
||||
)
|
||||
|
||||
val body = createRequest.copy(date = date, time = time, themeId = alreadyCreated.themeId)
|
||||
|
||||
runExceptionTest(
|
||||
token = token,
|
||||
method = HttpMethod.POST,
|
||||
endpoint = "/schedules",
|
||||
requestBody = body,
|
||||
expectedErrorCode = ScheduleErrorCode.SCHEDULE_ALREADY_EXISTS
|
||||
)
|
||||
}
|
||||
|
||||
test("입력된 날짜 + 시간이 현재 시간 이전이면 실패한다.") {
|
||||
val token = testAuthUtil.defaultHqAdminLogin()
|
||||
val body = createRequest.copy(LocalDate.now(), LocalTime.now().minusMinutes(1))
|
||||
|
||||
runExceptionTest(
|
||||
token = token,
|
||||
method = HttpMethod.POST,
|
||||
endpoint = "/schedules",
|
||||
requestBody = body,
|
||||
expectedErrorCode = ScheduleErrorCode.PAST_DATE_TIME
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
context("일정을 잠시 Hold 상태로 변경하여 중복 예약을 방지한다.") {
|
||||
context("권한이 없으면 접근할 수 없다.") {
|
||||
val endpoint = "/schedules/${INVALID_PK}/hold"
|
||||
|
||||
test("비회원") {
|
||||
runExceptionTest(
|
||||
method = HttpMethod.PATCH,
|
||||
endpoint = endpoint,
|
||||
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||
)
|
||||
}
|
||||
|
||||
test("관리자") {
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.defaultHqAdminLogin(),
|
||||
method = HttpMethod.PATCH,
|
||||
endpoint = endpoint,
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
test("해당 일정이 ${ScheduleStatus.AVAILABLE} 상태이면 정상 응답") {
|
||||
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||
adminToken = testAuthUtil.defaultHqAdminLogin(),
|
||||
request = createRequest
|
||||
)
|
||||
val schedule = dummyInitializer.createSchedule()
|
||||
|
||||
runTest(
|
||||
token = testAuthUtil.defaultUserLogin(),
|
||||
on = {
|
||||
patch("/schedules/${createdSchedule.id}/hold")
|
||||
post("/schedules/${schedule.id}/hold")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
}
|
||||
).also {
|
||||
val updatedSchedule = scheduleRepository.findByIdOrNull(createdSchedule.id)
|
||||
?: throw AssertionError("Unexpected Exception Occurred.")
|
||||
|
||||
updatedSchedule.status shouldBe ScheduleStatus.HOLD
|
||||
val updated = scheduleRepository.findByIdOrNull(schedule.id)!!
|
||||
updated.status shouldBe ScheduleStatus.HOLD
|
||||
}
|
||||
}
|
||||
|
||||
test("예약이 없으면 실패한다.") {
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.defaultUserLogin(),
|
||||
method = HttpMethod.PATCH,
|
||||
endpoint = "/schedules/$INVALID_PK/hold",
|
||||
expectedErrorCode = ScheduleErrorCode.SCHEDULE_NOT_FOUND
|
||||
)
|
||||
}
|
||||
|
||||
test("해당 일정이 ${ScheduleStatus.AVAILABLE} 상태가 아니면 실패한다.") {
|
||||
val adminToken = testAuthUtil.defaultHqAdminLogin()
|
||||
|
||||
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||
adminToken = adminToken,
|
||||
request = createRequest
|
||||
)
|
||||
|
||||
/*
|
||||
* 테스트를 위해 수정 API를 호출하여 상태를 HOLD 상태로 변경
|
||||
* 생성 API에서는 일정 생성 시 AVAILABLE을 기본 상태로 지정하기 때문.
|
||||
*/
|
||||
runTest(
|
||||
token = adminToken,
|
||||
using = {
|
||||
body(
|
||||
ScheduleUpdateRequest(status = ScheduleStatus.HOLD)
|
||||
)
|
||||
},
|
||||
on = {
|
||||
patch("/schedules/${createdSchedule.id}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
}
|
||||
)
|
||||
context("일정이 ${ScheduleStatus.AVAILABLE}이 아니면 실패한다.") {
|
||||
(ScheduleStatus.entries - ScheduleStatus.AVAILABLE).forEach {
|
||||
test("${it}") {
|
||||
val schedule = dummyInitializer.createSchedule(status = it)
|
||||
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.defaultUserLogin(),
|
||||
method = HttpMethod.PATCH,
|
||||
endpoint = "/schedules/${createdSchedule.id}/hold",
|
||||
method = HttpMethod.POST,
|
||||
endpoint = "/schedules/${schedule.id}/hold",
|
||||
expectedErrorCode = ScheduleErrorCode.SCHEDULE_NOT_AVAILABLE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
context("일정을 수정한다.") {
|
||||
val updateRequest = ScheduleUpdateRequest(
|
||||
time = LocalTime.now().plusHours(1),
|
||||
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 = testAuthUtil.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 = testAuthUtil.adminLogin(admin),
|
||||
method = HttpMethod.PATCH,
|
||||
requestBody = updateRequest,
|
||||
endpoint = endpoint,
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("정상 수정 및 감사 정보 변경 확인") {
|
||||
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||
adminToken = testAuthUtil.defaultHqAdminLogin(),
|
||||
request = createRequest.copy(
|
||||
date = LocalDate.now().plusDays(1),
|
||||
time = LocalTime.now().plusMinutes(1),
|
||||
)
|
||||
)
|
||||
|
||||
val otherAdminToken = testAuthUtil.adminLogin(
|
||||
AdminFixture.create(account = "otherAdmin", phone = "01099999999")
|
||||
)
|
||||
|
||||
runTest(
|
||||
token = otherAdminToken,
|
||||
using = {
|
||||
body(updateRequest)
|
||||
},
|
||||
on = {
|
||||
patch("/schedules/${createdSchedule.id}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
}
|
||||
).also {
|
||||
val updatedSchedule = scheduleRepository.findByIdOrNull(createdSchedule.id)!!
|
||||
|
||||
updatedSchedule.id shouldBe createdSchedule.id
|
||||
updatedSchedule.time.hour shouldBe updateRequest.time!!.hour
|
||||
updatedSchedule.time.minute shouldBe updateRequest.time.minute
|
||||
updatedSchedule.status shouldBe updateRequest.status
|
||||
updatedSchedule.updatedBy shouldNotBe createdSchedule.updatedBy
|
||||
updatedSchedule.updatedAt shouldBeAfter createdSchedule.updatedAt
|
||||
}
|
||||
}
|
||||
|
||||
test("입력값이 없으면 수정하지 않는다.") {
|
||||
val token = testAuthUtil.defaultHqAdminLogin()
|
||||
|
||||
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||
adminToken = token,
|
||||
request = createRequest
|
||||
)
|
||||
|
||||
runTest(
|
||||
token = token,
|
||||
using = {
|
||||
body(ScheduleUpdateRequest())
|
||||
},
|
||||
on = {
|
||||
patch("/schedules/${createdSchedule.id}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
}
|
||||
).also {
|
||||
val updatedSchedule = scheduleRepository.findByIdOrNull(createdSchedule.id)!!
|
||||
|
||||
updatedSchedule.id shouldBe createdSchedule.id
|
||||
updatedSchedule.updatedAt shouldBe createdSchedule.updatedAt
|
||||
}
|
||||
}
|
||||
|
||||
test("일정이 없으면 실패한다.") {
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.defaultHqAdminLogin(),
|
||||
method = HttpMethod.PATCH,
|
||||
requestBody = updateRequest,
|
||||
endpoint = "/schedules/${INVALID_PK}",
|
||||
expectedErrorCode = ScheduleErrorCode.SCHEDULE_NOT_FOUND
|
||||
)
|
||||
}
|
||||
|
||||
test("입력된 날짜 + 시간이 현재 시간 이전이면 실패한다.") {
|
||||
val token = testAuthUtil.defaultHqAdminLogin()
|
||||
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||
adminToken = token,
|
||||
request =
|
||||
|
||||
createRequest.copy(date = LocalDate.now(), time = LocalTime.now().plusMinutes(1))
|
||||
)
|
||||
|
||||
runExceptionTest(
|
||||
token = token,
|
||||
method = HttpMethod.PATCH,
|
||||
requestBody = updateRequest.copy(time = LocalTime.now().minusMinutes(1)),
|
||||
endpoint = "/schedules/${createdSchedule.id}",
|
||||
expectedErrorCode = ScheduleErrorCode.PAST_DATE_TIME
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
context("일정을 삭제한다.") {
|
||||
context("권한이 없으면 접근할 수 없다.") {
|
||||
val endpoint = "/schedules/${INVALID_PK}"
|
||||
|
||||
test("비회원") {
|
||||
runExceptionTest(
|
||||
method = HttpMethod.DELETE,
|
||||
endpoint = endpoint,
|
||||
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
|
||||
)
|
||||
}
|
||||
|
||||
test("회원") {
|
||||
runExceptionTest(
|
||||
token = testAuthUtil.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 = testAuthUtil.adminLogin(admin),
|
||||
method = HttpMethod.DELETE,
|
||||
endpoint = endpoint,
|
||||
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("정상 삭제") {
|
||||
val token = testAuthUtil.defaultHqAdminLogin()
|
||||
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||
adminToken = token,
|
||||
request = createRequest
|
||||
)
|
||||
|
||||
runTest(
|
||||
token = token,
|
||||
on = {
|
||||
delete("/schedules/${createdSchedule.id}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.NO_CONTENT.value())
|
||||
}
|
||||
).also {
|
||||
scheduleRepository.findByIdOrNull(createdSchedule.id) shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
test("예약 중이거나 예약이 완료된 일정이면 실패한다.") {
|
||||
val token = testAuthUtil.defaultHqAdminLogin()
|
||||
|
||||
val createdSchedule: ScheduleEntity = dummyInitializer.createSchedule(
|
||||
adminToken = token,
|
||||
request = createRequest
|
||||
)
|
||||
|
||||
/*
|
||||
* 테스트를 위해 수정 API를 호출하여 상태를 예약 중 상태로 변경
|
||||
* 생성 API에서는 일정 생성 시 AVAILABLE을 기본 상태로 지정하기 때문.
|
||||
*/
|
||||
runTest(
|
||||
token = token,
|
||||
using = {
|
||||
body(
|
||||
ScheduleUpdateRequest(status = ScheduleStatus.RESERVED)
|
||||
)
|
||||
},
|
||||
on = {
|
||||
patch("/schedules/${createdSchedule.id}")
|
||||
},
|
||||
expect = {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* 삭제 테스트
|
||||
*/
|
||||
runExceptionTest(
|
||||
token = token,
|
||||
method = HttpMethod.DELETE,
|
||||
endpoint = "/schedules/${createdSchedule.id}",
|
||||
expectedErrorCode = ScheduleErrorCode.SCHEDULE_IN_USE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user