diff --git a/src/main/java/org/hydev/clock_api/controller/RegistryController.java b/src/main/java/org/hydev/clock_api/controller/RegistryController.java index 6d9849a..9f2f2af 100644 --- a/src/main/java/org/hydev/clock_api/controller/RegistryController.java +++ b/src/main/java/org/hydev/clock_api/controller/RegistryController.java @@ -36,9 +36,9 @@ public class RegistryController { // [!] @RequestHeader(required = false) makes no need make another error handler. // [!] And also, ExceptionHandler of MissingRequestHeaderException cannot deal with all missing fields. @Pattern(regexp = User.RE_USERNAME, message = ErrorCode.USER_NAME_NOT_MATCH_REGEX) - @NotNull(message = ErrorCode.USER_NAME_IS_NULL) @RequestHeader(required = false) String username, + @RequestHeader String username, @Pattern(regexp = User.RE_PASSWORD, message = ErrorCode.USER_PASSWORD_NOT_MATCH_REGEX) - @NotNull(message = ErrorCode.USER_PASSWORD_IS_NULL) @RequestHeader(required = false) String password + @RequestHeader String password ) { // First, spring will check args. If not pass there regex, raise ConstraintViolationException. // Then, the aspect will check username if already exists. diff --git a/src/main/java/org/hydev/clock_api/error/ErrorCode.java b/src/main/java/org/hydev/clock_api/error/ErrorCode.java index 237d51f..6016578 100644 --- a/src/main/java/org/hydev/clock_api/error/ErrorCode.java +++ b/src/main/java/org/hydev/clock_api/error/ErrorCode.java @@ -2,16 +2,12 @@ package org.hydev.clock_api.error; public interface ErrorCode { - // Missing field in header. - String USER_NAME_IS_NULL = "A0101"; - String USER_PASSWORD_IS_NULL = "A0102"; - // Field not match regex. - String USER_NAME_NOT_MATCH_REGEX = "A0111"; - String USER_PASSWORD_NOT_MATCH_REGEX = "A0112"; + String USER_NAME_NOT_MATCH_REGEX = "A0101"; + String USER_PASSWORD_NOT_MATCH_REGEX = "A0102"; // Field already exists. - String USER_NAME_ALREADY_EXISTS = "A0121"; + String USER_NAME_ALREADY_EXISTS = "A0111"; // Inner system field is null. String INNER_USERNAME_IS_NULL = "B0101"; diff --git a/src/test/java/org/hydev/clock_api/UserRegisterDeleteNodeTest.kt b/src/test/java/org/hydev/clock_api/UserRegisterDeleteNodeTest.kt index 1f87c3c..05091e3 100644 --- a/src/test/java/org/hydev/clock_api/UserRegisterDeleteNodeTest.kt +++ b/src/test/java/org/hydev/clock_api/UserRegisterDeleteNodeTest.kt @@ -4,14 +4,16 @@ import org.hamcrest.Matchers import org.hydev.clock_api.entity.User import org.hydev.clock_api.error.ErrorCode.* import org.hydev.clock_api.repository.UserRepository -import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc import org.springframework.boot.test.context.SpringBootTest -import org.springframework.boot.test.context.SpringBootTest.* +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment import org.springframework.boot.test.web.client.TestRestTemplate import org.springframework.http.HttpEntity +import org.springframework.http.HttpHeaders import org.springframework.http.HttpMethod import org.springframework.http.HttpStatus import org.springframework.test.context.ActiveProfiles @@ -22,7 +24,6 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status import org.springframework.util.DigestUtils import org.springframework.util.LinkedMultiValueMap -import java.util.* import javax.validation.ConstraintViolationException // https://stackoverflow.com/questions/59097035/springboottest-vs-webmvctest-datajpatest-service-unit-tests-what-is-the-b @@ -63,39 +64,51 @@ class UserRegisterDeleteNodeTest { @Autowired private lateinit var restTemplate: TestRestTemplate + private fun Map.headersToHttpEntity(): HttpEntity { + val tempMultiValueMap = LinkedMultiValueMap() + this.forEach { tempMultiValueMap[it.key] = listOf(it.value) } + return HttpEntity(tempMultiValueMap) + } + + private fun Map.toHttpHeaders(): HttpHeaders { + val linkedMultiValueMap = LinkedMultiValueMap() + this.forEach { linkedMultiValueMap.add(it.key, it.value) } + return HttpHeaders(linkedMultiValueMap) + } + // Post to register node with headers, expect 406 and ErrorCodes. // todo: Using List instead of Array. - private fun pTRWHsE406AECs(headerMap: Map, expectedECList: Array) { - val tempMultiValueMap = LinkedMultiValueMap() - headerMap.forEach { tempMultiValueMap[it.key] = listOf(it.value) } - val httpEntity = HttpEntity(tempMultiValueMap) + private fun pTRWHsE406AECs(headerMap: Map, expectedECList: List) { + mockMvc.perform(post(REGISTER_NODE).headers(headerMap.toHttpHeaders())) + .andExpect(status().isNotAcceptable) + .andExpect(content().json(expectedECList.toString())) + } - // Using exchange to custom headers, etc. Args: (node, method, headers, forObject). - // https://stackoverflow.com/questions/16781680/http-get-with-headers-using-resttemplate + private fun pTRWHsEHS(headerMap: Map, expectedHttpStatus: HttpStatus) { val responseEntity = - restTemplate.exchange(REGISTER_NODE, HttpMethod.POST, httpEntity, Array::class.java) - - // Expect http status is 406 NOT ACCEPTABLE, and ErrorCode array are same. - assertEquals(HttpStatus.NOT_ACCEPTABLE, responseEntity.statusCode) - assertArrayEquals(expectedECList, responseEntity.body) + restTemplate.exchange( + REGISTER_NODE, HttpMethod.POST, + headerMap.headersToHttpEntity(), String::class.java + ) + assertEquals(expectedHttpStatus, responseEntity.statusCode) } @Test // [A0101, A0102, A0101 + A0102] M1 * 2 + M2. fun testWhenMissingField() { - pTRWHsE406AECs(mapOf(H_PASSWORD to V_PASSWORD), arrayOf(USER_NAME_IS_NULL)) - pTRWHsE406AECs(mapOf(H_USERNAME to V_USERNAME), arrayOf(USER_PASSWORD_IS_NULL)) - pTRWHsE406AECs(mapOf(), arrayOf(USER_NAME_IS_NULL, USER_PASSWORD_IS_NULL)) + pTRWHsEHS(mapOf(H_PASSWORD to V_PASSWORD), HttpStatus.BAD_REQUEST) + pTRWHsEHS(mapOf(H_USERNAME to V_USERNAME), HttpStatus.BAD_REQUEST) + pTRWHsEHS(mapOf(), HttpStatus.BAD_REQUEST) } @Test // [A0111, A0112, A0111 + A0112] W1 * 2 + W2. fun testWhenNotMatchRegex() { - pTRWHsE406AECs(mapOf(H_USERNAME to "", H_PASSWORD to V_PASSWORD), arrayOf(USER_NAME_NOT_MATCH_REGEX)) - pTRWHsE406AECs(mapOf(H_USERNAME to V_USERNAME, H_PASSWORD to ""), arrayOf(USER_PASSWORD_NOT_MATCH_REGEX)) + pTRWHsE406AECs(mapOf(H_USERNAME to "", H_PASSWORD to V_PASSWORD), listOf(USER_NAME_NOT_MATCH_REGEX)) + pTRWHsE406AECs(mapOf(H_USERNAME to V_USERNAME, H_PASSWORD to ""), listOf(USER_PASSWORD_NOT_MATCH_REGEX)) pTRWHsE406AECs( mapOf(H_USERNAME to "", H_PASSWORD to ""), - arrayOf(USER_NAME_NOT_MATCH_REGEX, USER_PASSWORD_NOT_MATCH_REGEX) + listOf(USER_NAME_NOT_MATCH_REGEX, USER_PASSWORD_NOT_MATCH_REGEX) ) } @@ -149,14 +162,14 @@ class UserRegisterDeleteNodeTest { // Post to delete node with headers and expect HttpStatus. private fun pTDWHsAEHS(headerMap: Map, expectedHttpStatus: HttpStatus) { - val tempMultiValueMap = LinkedMultiValueMap() - headerMap.forEach { tempMultiValueMap[it.key] = listOf(it.value) } - val httpEntity = HttpEntity(tempMultiValueMap) - - val responseEntity = restTemplate.exchange(DELETE_NODE, HttpMethod.POST, httpEntity, String::class.java) + val responseEntity = restTemplate.exchange( + DELETE_NODE, HttpMethod.POST, + headerMap.headersToHttpEntity(), String::class.java + ) assertEquals(expectedHttpStatus, responseEntity.statusCode) } + // -- New node test. @Test fun testDeleteUser() { mockMvc.perform(post(REGISTER_NODE).header(H_USERNAME, V_USERNAME).header(H_PASSWORD, V_PASSWORD))