diff --git a/src/main/kotlin/com/restaurant/be/user/domain/service/SignUpUserService.kt b/src/main/kotlin/com/restaurant/be/user/domain/service/SignUpUserService.kt index 5f3b0da..103007f 100644 --- a/src/main/kotlin/com/restaurant/be/user/domain/service/SignUpUserService.kt +++ b/src/main/kotlin/com/restaurant/be/user/domain/service/SignUpUserService.kt @@ -21,19 +21,18 @@ class SignUpUserService( @Transactional fun signUpUser(request: SignUpUserRequest): SignUpUserResponse { with(request) { - userRepository.findByNicknameOrEmail(nickname, email)?.let { - if (it.nickname == nickname) { - throw DuplicateUserNicknameException() - } + val user = userRepository.findByNicknameOrEmail(nickname, email) + if (user?.nickname == nickname) { + throw DuplicateUserNicknameException() + } - if (it.email == email) { - throw DuplicateUserEmailException() - } + if (user?.email == email) { + throw DuplicateUserEmailException() } - val user = userRepository.save(toEntity()) + val newUser = userRepository.save(toEntity()) - val token = tokenProvider.createTokens(email, user.roles) + val token = tokenProvider.createTokens(email, newUser.roles) redisRepository.setValue( redisRepository.REFRESH_PREFIX + email, @@ -41,7 +40,7 @@ class SignUpUserService( tokenProvider.refreshTokenValidityInMilliseconds, TimeUnit.MILLISECONDS ) - return SignUpUserResponse(user = user, token = token) + return SignUpUserResponse(user = newUser, token = token) } } } diff --git a/src/test/kotlin/com/restaurant/be/common/util/UserUtil.kt b/src/test/kotlin/com/restaurant/be/common/util/UserUtil.kt index 30ae488..357c921 100644 --- a/src/test/kotlin/com/restaurant/be/common/util/UserUtil.kt +++ b/src/test/kotlin/com/restaurant/be/common/util/UserUtil.kt @@ -1,5 +1,6 @@ package com.restaurant.be.common.util +import com.restaurant.be.common.password.PasswordService import com.restaurant.be.user.domain.entity.User import com.restaurant.be.user.repository.UserRepository import org.springframework.security.core.authority.SimpleGrantedAuthority @@ -8,7 +9,12 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedA import java.security.Principal fun setUpUser(email: String, userRepository: UserRepository): User { - val user = User(email = email, profileImageUrl = "") + val user = User( + email = email, + profileImageUrl = "", + nickname = "nickname", + password = "password".run(PasswordService::hashPassword) + ) userRepository.save(user) SecurityContextHolder.getContext().authentication = diff --git a/src/test/kotlin/com/restaurant/be/user/presentation/controller/CheckNicknameControllerTest.kt b/src/test/kotlin/com/restaurant/be/user/presentation/controller/CheckNicknameControllerTest.kt new file mode 100644 index 0000000..080bc0d --- /dev/null +++ b/src/test/kotlin/com/restaurant/be/user/presentation/controller/CheckNicknameControllerTest.kt @@ -0,0 +1,98 @@ +package com.restaurant.be.user.presentation.controller + +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.module.kotlin.KotlinModule +import com.restaurant.be.common.CustomDescribeSpec +import com.restaurant.be.common.IntegrationTest +import com.restaurant.be.common.PageDeserializer +import com.restaurant.be.common.response.CommonResponse +import com.restaurant.be.common.util.setUpUser +import com.restaurant.be.restaurant.presentation.controller.dto.common.RestaurantDto +import com.restaurant.be.user.presentation.dto.CheckNicknameResponse +import com.restaurant.be.user.repository.UserRepository +import io.kotest.matchers.shouldBe +import org.springframework.data.domain.Page +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import org.springframework.transaction.annotation.Transactional +import java.nio.charset.Charset + +@IntegrationTest +@Transactional +class CheckNicknameControllerTest( + private val mockMvc: MockMvc, + private val userRepository: UserRepository +) : CustomDescribeSpec() { + private val baseUrl = "/v1/users" + private val objectMapper: ObjectMapper = ObjectMapper().registerModule(KotlinModule()).apply { + val module = SimpleModule() + module.addDeserializer(Page::class.java, PageDeserializer(RestaurantDto::class.java)) + this.registerModule(module) + } + + init { + beforeEach { + setUpUser("test@gmail.com", userRepository) + } + + describe("#checkNickname basic test") { + it("when nickname is not used should return isDuplicate false") { + // given + val nickname = "test" + + // when + val result = mockMvc.perform( + get("$baseUrl/check-nickname") + .param("nickname", nickname) + ).also { + println(it.andReturn().response.contentAsString) + } + .andExpect(status().isOk) + .andExpect(jsonPath("$.result").value("SUCCESS")) + .andReturn() + + val responseContent = result.response.getContentAsString(Charset.forName("UTF-8")) + val responseType = + object : TypeReference>() {} + val actualResult: CommonResponse = objectMapper.readValue( + responseContent, + responseType + ) + + // then + actualResult.data!!.isDuplicate shouldBe false + } + + it("when nickname is used should throw DuplicateUserNicknameException") { + // given + val existedUserNickname = userRepository.findByEmail("test@gmail.com")?.nickname ?: "" + + // when + val result = mockMvc.perform( + get("$baseUrl/check-nickname") + .param("nickname", existedUserNickname) + ).also { + println(it.andReturn().response.contentAsString) + } + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.result").value("FAIL")) + .andReturn() + + val responseContent = result.response.getContentAsString(Charset.forName("UTF-8")) + val responseType = + object : TypeReference>() {} + val actualResult: CommonResponse = objectMapper.readValue( + responseContent, + responseType + ) + + // then + actualResult.message shouldBe "이미 존재 하는 닉네임 입니다." + } + } + } +} diff --git a/src/test/kotlin/com/restaurant/be/user/presentation/controller/DeleteUserControllerTest.kt b/src/test/kotlin/com/restaurant/be/user/presentation/controller/DeleteUserControllerTest.kt new file mode 100644 index 0000000..11c2d25 --- /dev/null +++ b/src/test/kotlin/com/restaurant/be/user/presentation/controller/DeleteUserControllerTest.kt @@ -0,0 +1,93 @@ +package com.restaurant.be.user.presentation.controller + +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.module.kotlin.KotlinModule +import com.restaurant.be.common.CustomDescribeSpec +import com.restaurant.be.common.IntegrationTest +import com.restaurant.be.common.PageDeserializer +import com.restaurant.be.common.response.CommonResponse +import com.restaurant.be.common.util.setUpUser +import com.restaurant.be.restaurant.presentation.controller.dto.common.RestaurantDto +import com.restaurant.be.user.repository.UserRepository +import io.kotest.matchers.shouldBe +import org.springframework.data.domain.Page +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import org.springframework.transaction.annotation.Transactional +import java.nio.charset.Charset + +@IntegrationTest +@Transactional +class DeleteUserControllerTest( + private val mockMvc: MockMvc, + private val userRepository: UserRepository +) : CustomDescribeSpec() { + private val baseUrl = "/v1/users" + private val objectMapper: ObjectMapper = ObjectMapper().registerModule(KotlinModule()).apply { + val module = SimpleModule() + module.addDeserializer(Page::class.java, PageDeserializer(RestaurantDto::class.java)) + this.registerModule(module) + } + + init { + beforeEach { + setUpUser("test@gmail.com", userRepository) + } + + describe("#deleteUser basic test") { + it("when user delete should return success") { + // given + // when + val result = mockMvc.perform( + delete("$baseUrl") + ).also { + println(it.andReturn().response.contentAsString) + } + .andExpect(status().isOk) + .andExpect(jsonPath("$.result").value("SUCCESS")) + .andReturn() + + val responseContent = result.response.getContentAsString(Charset.forName("UTF-8")) + val responseType = + object : TypeReference>() {} + val actualResult: CommonResponse = objectMapper.readValue( + responseContent, + responseType + ) + + // then + actualResult.result shouldBe CommonResponse.Result.SUCCESS + } + + it("when not exists user delete should return fail") { + // given + userRepository.deleteAll() + + // when + val result = mockMvc.perform( + delete("$baseUrl") + ).also { + println(it.andReturn().response.contentAsString) + } + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.result").value("FAIL")) + .andReturn() + + val responseContent = result.response.getContentAsString(Charset.forName("UTF-8")) + val responseType = + object : TypeReference>() {} + val actualResult: CommonResponse = objectMapper.readValue( + responseContent, + responseType + ) + + // then + actualResult.message shouldBe "존재 하지 않는 유저 입니다." + } + } + } +} diff --git a/src/test/kotlin/com/restaurant/be/user/presentation/controller/GetUserControllerTest.kt b/src/test/kotlin/com/restaurant/be/user/presentation/controller/GetUserControllerTest.kt new file mode 100644 index 0000000..e5096ce --- /dev/null +++ b/src/test/kotlin/com/restaurant/be/user/presentation/controller/GetUserControllerTest.kt @@ -0,0 +1,97 @@ +package com.restaurant.be.user.presentation.controller + +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.module.kotlin.KotlinModule +import com.restaurant.be.common.CustomDescribeSpec +import com.restaurant.be.common.IntegrationTest +import com.restaurant.be.common.PageDeserializer +import com.restaurant.be.common.response.CommonResponse +import com.restaurant.be.common.util.setUpUser +import com.restaurant.be.restaurant.presentation.controller.dto.common.RestaurantDto +import com.restaurant.be.user.presentation.dto.GetUserResponse +import com.restaurant.be.user.repository.UserRepository +import io.kotest.matchers.shouldBe +import org.springframework.data.domain.Page +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import org.springframework.transaction.annotation.Transactional +import java.nio.charset.Charset + +@IntegrationTest +@Transactional +class GetUserControllerTest( + private val mockMvc: MockMvc, + private val userRepository: UserRepository +) : CustomDescribeSpec() { + private val baseUrl = "/v1/users" + private val objectMapper: ObjectMapper = ObjectMapper().registerModule(KotlinModule()).apply { + val module = SimpleModule() + module.addDeserializer(Page::class.java, PageDeserializer(RestaurantDto::class.java)) + this.registerModule(module) + } + + init { + beforeEach { + setUpUser("test@gmail.com", userRepository) + } + + describe("#getUser basic test") { + it("when existed user should return user info") { + // given + val user = userRepository.findByEmail("test@gmail.com") ?: throw Exception("User not found") + + // when + val result = mockMvc.perform( + get("$baseUrl/${user.id}") + ).also { + println(it.andReturn().response.contentAsString) + } + .andExpect(status().isOk) + .andExpect(jsonPath("$.result").value("SUCCESS")) + .andReturn() + + val responseContent = result.response.getContentAsString(Charset.forName("UTF-8")) + val responseType = + object : TypeReference>() {} + val actualResult: CommonResponse = objectMapper.readValue( + responseContent, + responseType + ) + + // then + actualResult.data!!.userDto.id shouldBe user.id + actualResult.data!!.userDto.email shouldBe user.email + actualResult.data!!.userDto.nickname shouldBe user.nickname + actualResult.data!!.userDto.profileImageUrl shouldBe user.profileImageUrl + } + + it("when not existed user should fail") { + // given + // when + val result = mockMvc.perform( + get("$baseUrl/12345") + ).also { + println(it.andReturn().response.contentAsString) + } + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.result").value("FAIL")) + .andReturn() + + val responseContent = result.response.getContentAsString(Charset.forName("UTF-8")) + val responseType = + object : TypeReference>() {} + val actualResult: CommonResponse = objectMapper.readValue( + responseContent, + responseType + ) + + // then + actualResult.message shouldBe "존재 하지 않는 유저 입니다." + } + } + } +} diff --git a/src/test/kotlin/com/restaurant/be/user/presentation/controller/SignInUserControllerTest.kt b/src/test/kotlin/com/restaurant/be/user/presentation/controller/SignInUserControllerTest.kt new file mode 100644 index 0000000..d5ad405 --- /dev/null +++ b/src/test/kotlin/com/restaurant/be/user/presentation/controller/SignInUserControllerTest.kt @@ -0,0 +1,149 @@ +package com.restaurant.be.user.presentation.controller + +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.module.kotlin.KotlinModule +import com.restaurant.be.common.CustomDescribeSpec +import com.restaurant.be.common.IntegrationTest +import com.restaurant.be.common.PageDeserializer +import com.restaurant.be.common.response.CommonResponse +import com.restaurant.be.common.util.setUpUser +import com.restaurant.be.restaurant.presentation.controller.dto.common.RestaurantDto +import com.restaurant.be.user.presentation.dto.SignInUserResponse +import com.restaurant.be.user.repository.UserRepository +import io.kotest.matchers.shouldBe +import org.springframework.data.domain.Page +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import org.springframework.transaction.annotation.Transactional +import java.nio.charset.Charset + +@IntegrationTest +@Transactional +class SignInUserControllerTest( + private val mockMvc: MockMvc, + private val userRepository: UserRepository +) : CustomDescribeSpec() { + private val baseUrl = "/v1/users/email" + private val objectMapper: ObjectMapper = ObjectMapper().registerModule(KotlinModule()).apply { + val module = SimpleModule() + module.addDeserializer(Page::class.java, PageDeserializer(RestaurantDto::class.java)) + this.registerModule(module) + } + + init { + beforeEach { + setUpUser("test@gmail.com", userRepository) + } + + describe("#signIn basic test") { + it("when email and password is correct should return token") { + // given + val user = userRepository.findByEmail("test@gmail.com")!! + + // when + val result = mockMvc.perform( + post("$baseUrl/sign-in") + .content( + objectMapper.writeValueAsString( + mapOf( + "email" to user.email, + "password" to "password" + ) + ) + ) + .contentType("application/json") + ).also { + println(it.andReturn().response.contentAsString) + } + .andExpect(status().isOk) + .andExpect(jsonPath("$.result").value("SUCCESS")) + .andReturn() + + val responseContent = result.response.getContentAsString(Charset.forName("UTF-8")) + val responseType = + object : TypeReference>() {} + val actualResult: CommonResponse = objectMapper.readValue( + responseContent, + responseType + ) + + // then + actualResult.data!!.userDto.email shouldBe user.email + } + + it("when email is not exist should throw NotFoundUserEmailException") { + // given + val notFoundEmail = "notfound@gmail.com" + + // when + val result = mockMvc.perform( + post("$baseUrl/sign-in") + .content( + objectMapper.writeValueAsString( + mapOf( + "email" to notFoundEmail, + "password" to "test1234" + ) + ) + ) + .contentType("application/json") + ).also { + println(it.andReturn().response.contentAsString) + } + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.result").value("FAIL")) + .andReturn() + + val responseContent = result.response.getContentAsString(Charset.forName("UTF-8")) + val responseType = + object : TypeReference>() {} + val actualResult: CommonResponse = objectMapper.readValue( + responseContent, + responseType + ) + + // then + actualResult.message shouldBe "존재 하지 않는 유저 이메일 입니다." + } + + it("when password is incorrect should throw InvalidPasswordException") { + // given + val user = userRepository.findByEmail("test@gmail.com") + + // when + val result = mockMvc.perform( + post("$baseUrl/sign-in") + .content( + objectMapper.writeValueAsString( + mapOf( + "email" to user?.email, + "password" to "test1234" + ) + ) + ) + .contentType("application/json") + ).also { + println(it.andReturn().response.contentAsString) + } + .andExpect(status().isUnauthorized) + .andExpect(jsonPath("$.result").value("FAIL")) + .andReturn() + + val responseContent = result.response.getContentAsString(Charset.forName("UTF-8")) + val responseType = + object : TypeReference>() {} + val actualResult: CommonResponse = objectMapper.readValue( + responseContent, + responseType + ) + + // then + actualResult.message shouldBe "패스워드가 일치 하지 않습니다." + } + } + } +} diff --git a/src/test/kotlin/com/restaurant/be/user/presentation/controller/SignUpUserControllerTest.kt b/src/test/kotlin/com/restaurant/be/user/presentation/controller/SignUpUserControllerTest.kt new file mode 100644 index 0000000..68ac752 --- /dev/null +++ b/src/test/kotlin/com/restaurant/be/user/presentation/controller/SignUpUserControllerTest.kt @@ -0,0 +1,157 @@ +package com.restaurant.be.user.presentation.controller + +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.module.kotlin.KotlinModule +import com.restaurant.be.common.CustomDescribeSpec +import com.restaurant.be.common.IntegrationTest +import com.restaurant.be.common.PageDeserializer +import com.restaurant.be.common.response.CommonResponse +import com.restaurant.be.common.util.setUpUser +import com.restaurant.be.restaurant.presentation.controller.dto.common.RestaurantDto +import com.restaurant.be.user.presentation.dto.SignUpUserResponse +import com.restaurant.be.user.repository.UserRepository +import io.kotest.matchers.shouldBe +import org.springframework.data.domain.Page +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.* +import org.springframework.transaction.annotation.Transactional +import java.nio.charset.Charset + +@IntegrationTest +@Transactional +class SignUpUserControllerTest( + private val mockMvc: MockMvc, + private val userRepository: UserRepository +) : CustomDescribeSpec() { + private val baseUrl = "/v1/users" + private val objectMapper: ObjectMapper = ObjectMapper().registerModule(KotlinModule()).apply { + val module = SimpleModule() + module.addDeserializer(Page::class.java, PageDeserializer(RestaurantDto::class.java)) + this.registerModule(module) + } + + init { + beforeEach { + setUpUser("test@gmail.com", userRepository) + } + + describe("#signUpUser basic test") { + it("when email and password is correct should return token") { + // given + val email = "newUser@gmail.com" + val password = "password" + val nickname = "newUser" + val profileImageUrl = "profileImageUrl" + + // when + val result = mockMvc.perform( + post("$baseUrl/email/sign-up") + .content( + objectMapper.writeValueAsString( + mapOf( + "email" to email, + "password" to password, + "nickname" to nickname, + "profileImageUrl" to profileImageUrl + ) + ) + ) + .contentType("application/json") + ).also { + println(it.andReturn().response.contentAsString) + }.andExpect(status().isOk) + .andExpect(jsonPath("$.result").value("SUCCESS")) + .andReturn() + + val responseContent = result.response.getContentAsString(Charset.forName("UTF-8")) + val responseType = + object : TypeReference>() {} + val actualResult: CommonResponse = objectMapper.readValue( + responseContent, + responseType + ) + + // then + actualResult.data!!.userDto.email shouldBe email + } + + it("when existed nickname should throw DuplicateUserNicknameException") { + // given + val existedUserNickname = + userRepository.findByEmail("test@gmail.com")?.nickname ?: "" + + // when + val result = mockMvc.perform( + post("$baseUrl/email/sign-up") + .content( + objectMapper.writeValueAsString( + mapOf( + "email" to "test@test.com", + "password" to "123456789", + "nickname" to existedUserNickname, + "profileImageUrl" to "" + ) + ) + ) + .contentType("application/json") + ).also { + println(it.andReturn().response.contentAsString) + } + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.result").value("FAIL")) + .andReturn() + + val responseContent = result.response.getContentAsString(Charset.forName("UTF-8")) + val responseType = + object : TypeReference>() {} + val actualResult: CommonResponse = objectMapper.readValue( + responseContent, + responseType + ) + + // then + actualResult.message shouldBe "이미 존재 하는 닉네임 입니다." + } + + it("when existed email should throw DuplicateUserEmailException") { + // given + val existedUserEmail = "test@gmail.com" + + // when + val result = mockMvc.perform( + post("$baseUrl/email/sign-up") + .content( + objectMapper.writeValueAsString( + mapOf( + "email" to existedUserEmail, + "password" to "123456789", + "nickname" to "test", + "profileImageUrl" to "" + ) + ) + ) + .contentType("application/json") + ).also { + println(it.andReturn().response.contentAsString) + } + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.result").value("FAIL")) + .andReturn() + + val responseContent = result.response.getContentAsString(Charset.forName("UTF-8")) + val responseType = + object : TypeReference>() {} + val actualResult: CommonResponse = objectMapper.readValue( + responseContent, + responseType + ) + + // then + actualResult.message shouldBe "이미 존재 하는 이메일 입니다." + } + } + } +}