178 lines
5.7 KiB
Kotlin

package roomescape.util
import io.restassured.module.kotlin.extensions.Extract
import io.restassured.module.kotlin.extensions.Given
import io.restassured.module.kotlin.extensions.Then
import io.restassured.module.kotlin.extensions.When
import io.restassured.response.Response
import io.restassured.response.ValidatableResponse
import io.restassured.specification.RequestSpecification
import org.springframework.data.repository.findByIdOrNull
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import roomescape.admin.infrastructure.persistence.AdminEntity
import roomescape.admin.infrastructure.persistence.AdminRepository
import roomescape.auth.web.LoginRequest
import roomescape.auth.web.LoginRequestV2
import roomescape.common.config.next
import roomescape.common.dto.PrincipalType
import roomescape.member.infrastructure.persistence.*
import roomescape.member.web.UserCreateRequest
import roomescape.member.web.toEntity
class AuthUtil(
private val memberRepository: MemberRepository,
private val userRepository: UserRepository,
private val adminRepository: AdminRepository
) {
fun login(email: String, password: String, role: Role = Role.MEMBER): String {
if (!memberRepository.existsByEmail(email)) {
memberRepository.save(
MemberEntity(
_id = tsidFactory.next(),
email = email,
password = password,
name = email.split("@").first(),
role = role
)
)
}
return Given {
contentType(MediaType.APPLICATION_JSON_VALUE)
body(LoginRequest(email, password))
} When {
post("/login")
} Then {
statusCode(200)
} Extract {
path("data.accessToken")
}
}
fun loginAsAdmin(): String {
return login(MemberFixture.admin.email, MemberFixture.admin.password, Role.ADMIN)
}
fun loginAsUser(): String {
return login(MemberFixture.user.email, MemberFixture.user.password)
}
fun getUser(): MemberEntity = memberRepository.findByEmailAndPassword(
MemberFixture.user.email,
MemberFixture.user.password
) ?: throw AssertionError("Unexpected Exception Occurred.")
fun createAdmin(admin: AdminEntity): AdminEntity {
return adminRepository.save(admin)
}
fun signup(request: UserCreateRequest): UserEntity {
val userId: Long = Given {
contentType(MediaType.APPLICATION_JSON_VALUE)
body(request)
} When {
post("/users")
} Then {
statusCode(HttpStatus.OK.value())
} Extract {
path("data.id")
}
return userRepository.findByIdOrNull(userId)
?: throw AssertionError("Unexpected Exception Occurred.")
}
fun adminLogin(admin: AdminEntity): String {
if (adminRepository.findByAccount(admin.account) == null) {
adminRepository.save(admin)
}
return Given {
contentType(MediaType.APPLICATION_JSON_VALUE)
body(LoginRequestV2(account = admin.account, password = admin.password, principalType = PrincipalType.ADMIN))
} When {
post("/auth/login")
} Then {
statusCode(200)
} Extract {
path("data.accessToken")
}
}
fun defaultAdminLogin(): String = adminLogin(AdminFixture.default)
fun userLogin(user: UserEntity): String {
if (userRepository.findByEmail(user.email) == null) {
userRepository.save(user)
}
return Given {
contentType(MediaType.APPLICATION_JSON_VALUE)
body(LoginRequestV2(account = user.email, password = user.password, principalType = PrincipalType.USER))
} When {
post("/auth/login")
} Then {
statusCode(200)
} Extract {
path("data.accessToken")
}
}
fun defaultUserLogin(): String = userLogin(UserFixture.default)
}
fun runTest(
token: String? = null,
using: RequestSpecification.() -> RequestSpecification = { this },
on: RequestSpecification.() -> Response,
expect: ValidatableResponse.() -> Unit
): ValidatableResponse {
return Given {
contentType(MediaType.APPLICATION_JSON_VALUE)
token?.also { header("Authorization", "Bearer $token") }
using()
} When {
on()
} Then {
expect()
}
}
/**
* @param props: RestAssured 응답 Body 에서 존재 & Null 여부를 확인할 프로퍼티 이름
*/
fun ValidatableResponse.assertProperties(props: Set<String>, propsNameIfList: String? = null) {
val jsonDefaultPath = propsNameIfList?.let { "data.$propsNameIfList" } ?: "data"
val json = extract().jsonPath().get<Any>(jsonDefaultPath)
fun checkMap(map: Map<*, *>) {
val responseKeys = map.keys.map { it.toString() }.toSet()
val expectedKeys = props
val missing = expectedKeys - responseKeys
val extra = responseKeys - expectedKeys
require(missing.isEmpty() && extra.isEmpty()) {
buildString {
if (missing.isNotEmpty()) append("Missing keys: $missing. ")
if (extra.isNotEmpty()) append("Unexpected keys: $extra.")
}
}
expectedKeys.forEach { key ->
require(map[key] != null) { "Property '$key' is null" }
}
}
when (json) {
is List<*> -> json.forEach { item ->
val map = item as? Map<*, *> ?: error("Expected Map but got ${item?.javaClass}")
checkMap(map)
}
is Map<*, *> -> checkMap(json)
else -> error("Unexpected data type: ${json::class}")
}
}