Commit b1259b3b3bde2ab3e087509a2c1ae1e6fd3e58a0
1 parent
e00bb2bd
test(mod): module create integration coverage REQ-MOD-001
Showing
3 changed files
with
111 additions
and
1 deletions
backend/pom.xml
| @@ -99,6 +99,17 @@ | @@ -99,6 +99,17 @@ | ||
| 99 | <groupId>org.springframework.boot</groupId> | 99 | <groupId>org.springframework.boot</groupId> |
| 100 | <artifactId>spring-boot-maven-plugin</artifactId> | 100 | <artifactId>spring-boot-maven-plugin</artifactId> |
| 101 | </plugin> | 101 | </plugin> |
| 102 | + <plugin> | ||
| 103 | + <groupId>org.apache.maven.plugins</groupId> | ||
| 104 | + <artifactId>maven-surefire-plugin</artifactId> | ||
| 105 | + <configuration> | ||
| 106 | + <includes> | ||
| 107 | + <include>**/*Test.java</include> | ||
| 108 | + <include>**/*Tests.java</include> | ||
| 109 | + <include>**/*IT.java</include> | ||
| 110 | + </includes> | ||
| 111 | + </configuration> | ||
| 112 | + </plugin> | ||
| 102 | </plugins> | 113 | </plugins> |
| 103 | </build> | 114 | </build> |
| 104 | </project> | 115 | </project> |
backend/src/main/java/com/xly/erp/common/security/SecurityContextHelper.java
| 1 | package com.xly.erp.common.security; | 1 | package com.xly.erp.common.security; |
| 2 | 2 | ||
| 3 | +import org.springframework.security.authentication.AnonymousAuthenticationToken; | ||
| 3 | import org.springframework.security.core.Authentication; | 4 | import org.springframework.security.core.Authentication; |
| 4 | import org.springframework.security.core.context.SecurityContextHolder; | 5 | import org.springframework.security.core.context.SecurityContextHolder; |
| 5 | 6 | ||
| @@ -10,7 +11,7 @@ public final class SecurityContextHelper { | @@ -10,7 +11,7 @@ public final class SecurityContextHelper { | ||
| 10 | 11 | ||
| 11 | public static String currentUserNo() { | 12 | public static String currentUserNo() { |
| 12 | Authentication auth = SecurityContextHolder.getContext().getAuthentication(); | 13 | Authentication auth = SecurityContextHolder.getContext().getAuthentication(); |
| 13 | - if (auth == null || auth.getPrincipal() == null) { | 14 | + if (auth == null || auth instanceof AnonymousAuthenticationToken) { |
| 14 | return null; | 15 | return null; |
| 15 | } | 16 | } |
| 16 | Object p = auth.getPrincipal(); | 17 | Object p = auth.getPrincipal(); |
backend/src/test/java/com/xly/erp/module/mod/controller/ModuleControllerIT.java
| @@ -73,6 +73,104 @@ class ModuleControllerIT { | @@ -73,6 +73,104 @@ class ModuleControllerIT { | ||
| 73 | assertThat(row.get("sCreatedBy")).isEqualTo("ADMIN001"); | 73 | assertThat(row.get("sCreatedBy")).isEqualTo("ADMIN001"); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | + @Test | ||
| 77 | + void postEmptyBody_returns40001_withFieldHint() throws Exception { | ||
| 78 | + String token = testJwtHelper.signFor("ADMIN001"); | ||
| 79 | + HttpHeaders headers = jsonHeaders(); | ||
| 80 | + headers.set("Authorization", "Bearer " + token); | ||
| 81 | + | ||
| 82 | + ResponseEntity<String> resp = rest.exchange( | ||
| 83 | + url(), | ||
| 84 | + HttpMethod.POST, | ||
| 85 | + new HttpEntity<>("{}", headers), | ||
| 86 | + String.class); | ||
| 87 | + | ||
| 88 | + JsonNode body = objectMapper.readTree(resp.getBody()); | ||
| 89 | + assertThat(body.get("code").asInt()).isEqualTo(40001); | ||
| 90 | + assertThat(body.get("msg").asText()).containsAnyOf( | ||
| 91 | + "sProcedureName", "sDisplayType", "sModuleType", "sManageDeptEn", "sModuleNameZh"); | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + @Test | ||
| 95 | + void postInvalidDisplayType_returns40010() throws Exception { | ||
| 96 | + String token = testJwtHelper.signFor("ADMIN001"); | ||
| 97 | + HttpHeaders headers = jsonHeaders(); | ||
| 98 | + headers.set("Authorization", "Bearer " + token); | ||
| 99 | + Map<String, Object> bad = validBody("sp_test_bad_type", "枚举非法"); | ||
| 100 | + bad.put("sDisplayType", "火星"); | ||
| 101 | + | ||
| 102 | + ResponseEntity<String> resp = rest.exchange( | ||
| 103 | + url(), HttpMethod.POST, new HttpEntity<>(bad, headers), String.class); | ||
| 104 | + | ||
| 105 | + JsonNode body = objectMapper.readTree(resp.getBody()); | ||
| 106 | + assertThat(body.get("code").asInt()).isEqualTo(40010); | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + @Test | ||
| 110 | + void postDuplicateProcedureName_returns40020() throws Exception { | ||
| 111 | + String token = testJwtHelper.signFor("ADMIN001"); | ||
| 112 | + HttpHeaders headers = jsonHeaders(); | ||
| 113 | + headers.set("Authorization", "Bearer " + token); | ||
| 114 | + Map<String, Object> first = validBody("sp_test_dup", "首次"); | ||
| 115 | + ResponseEntity<String> r1 = rest.exchange( | ||
| 116 | + url(), HttpMethod.POST, new HttpEntity<>(first, headers), String.class); | ||
| 117 | + assertThat(objectMapper.readTree(r1.getBody()).get("code").asInt()).isZero(); | ||
| 118 | + | ||
| 119 | + Map<String, Object> dup = validBody("sp_test_dup", "重复"); | ||
| 120 | + ResponseEntity<String> r2 = rest.exchange( | ||
| 121 | + url(), HttpMethod.POST, new HttpEntity<>(dup, headers), String.class); | ||
| 122 | + JsonNode body = objectMapper.readTree(r2.getBody()); | ||
| 123 | + assertThat(body.get("code").asInt()).isEqualTo(40020); | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + @Test | ||
| 127 | + void postWithMissingParent_returns40021() throws Exception { | ||
| 128 | + String token = testJwtHelper.signFor("ADMIN001"); | ||
| 129 | + HttpHeaders headers = jsonHeaders(); | ||
| 130 | + headers.set("Authorization", "Bearer " + token); | ||
| 131 | + Map<String, Object> orphan = validBody("sp_test_orphan", "缺父"); | ||
| 132 | + orphan.put("iParentId", 99999999); | ||
| 133 | + | ||
| 134 | + ResponseEntity<String> resp = rest.exchange( | ||
| 135 | + url(), HttpMethod.POST, new HttpEntity<>(orphan, headers), String.class); | ||
| 136 | + | ||
| 137 | + JsonNode body = objectMapper.readTree(resp.getBody()); | ||
| 138 | + assertThat(body.get("code").asInt()).isEqualTo(40021); | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + @Test | ||
| 142 | + void postWithoutJwt_permitAllStub_returns200_andCreatedBySTUBADMIN() throws Exception { | ||
| 143 | + HttpHeaders headers = jsonHeaders(); | ||
| 144 | + Map<String, Object> body = validBody("sp_test_nojwt", "无JWT"); | ||
| 145 | + | ||
| 146 | + ResponseEntity<String> resp = rest.exchange( | ||
| 147 | + url(), HttpMethod.POST, new HttpEntity<>(body, headers), String.class); | ||
| 148 | + | ||
| 149 | + JsonNode jb = objectMapper.readTree(resp.getBody()); | ||
| 150 | + assertThat(jb.get("code").asInt()).isZero(); | ||
| 151 | + int newId = jb.get("data").get("iIncrement").asInt(); | ||
| 152 | + String createdBy = jdbcTemplate.queryForObject( | ||
| 153 | + "SELECT sCreatedBy FROM tModule WHERE iIncrement = ?", String.class, newId); | ||
| 154 | + assertThat(createdBy).isEqualTo("STUB_ADMIN"); | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + @Test | ||
| 158 | + void postWithTamperedJwt_returns20001() throws Exception { | ||
| 159 | + HttpHeaders headers = jsonHeaders(); | ||
| 160 | + headers.set("Authorization", "Bearer not.a.real.jwt"); | ||
| 161 | + Map<String, Object> body = validBody("sp_test_tampered", "伪JWT"); | ||
| 162 | + | ||
| 163 | + ResponseEntity<String> resp = rest.exchange( | ||
| 164 | + url(), HttpMethod.POST, new HttpEntity<>(body, headers), String.class); | ||
| 165 | + | ||
| 166 | + JsonNode jb = objectMapper.readTree(resp.getBody()); | ||
| 167 | + assertThat(jb.get("code").asInt()).isEqualTo(20001); | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + private String url() { | ||
| 171 | + return "http://localhost:" + port + "/api/mod/modules"; | ||
| 172 | + } | ||
| 173 | + | ||
| 76 | static HttpHeaders jsonHeaders() { | 174 | static HttpHeaders jsonHeaders() { |
| 77 | HttpHeaders h = new HttpHeaders(); | 175 | HttpHeaders h = new HttpHeaders(); |
| 78 | h.setContentType(MediaType.APPLICATION_JSON); | 176 | h.setContentType(MediaType.APPLICATION_JSON); |