Commit ac7704a5c1bfdcc95933bd8286515a252f144f6d

Authored by zichun
1 parent 340cde10

test(usr): user update integration coverage REQ-USR-002

backend/src/main/java/com/xly/erp/module/usr/controller/UserController.java
@@ -2,9 +2,12 @@ package com.xly.erp.module.usr.controller; @@ -2,9 +2,12 @@ package com.xly.erp.module.usr.controller;
2 2
3 import com.xly.erp.common.response.Result; 3 import com.xly.erp.common.response.Result;
4 import com.xly.erp.module.usr.dto.CreateUserDTO; 4 import com.xly.erp.module.usr.dto.CreateUserDTO;
  5 +import com.xly.erp.module.usr.dto.UpdateUserDTO;
5 import com.xly.erp.module.usr.service.UserService; 6 import com.xly.erp.module.usr.service.UserService;
6 import jakarta.validation.Valid; 7 import jakarta.validation.Valid;
  8 +import org.springframework.web.bind.annotation.PathVariable;
7 import org.springframework.web.bind.annotation.PostMapping; 9 import org.springframework.web.bind.annotation.PostMapping;
  10 +import org.springframework.web.bind.annotation.PutMapping;
8 import org.springframework.web.bind.annotation.RequestBody; 11 import org.springframework.web.bind.annotation.RequestBody;
9 import org.springframework.web.bind.annotation.RequestMapping; 12 import org.springframework.web.bind.annotation.RequestMapping;
10 import org.springframework.web.bind.annotation.RestController; 13 import org.springframework.web.bind.annotation.RestController;
@@ -25,4 +28,11 @@ public class UserController { @@ -25,4 +28,11 @@ public class UserController {
25 public Result<Map<String, Object>> create(@Valid @RequestBody CreateUserDTO dto) { 28 public Result<Map<String, Object>> create(@Valid @RequestBody CreateUserDTO dto) {
26 return Result.ok(userService.create(dto)); 29 return Result.ok(userService.create(dto));
27 } 30 }
  31 +
  32 + @PutMapping("/users/{id}")
  33 + public Result<Map<String, Object>> update(@PathVariable Integer id,
  34 + @Valid @RequestBody UpdateUserDTO dto) {
  35 + Integer updated = userService.update(id, dto);
  36 + return Result.ok(Map.of("iIncrement", updated));
  37 + }
28 } 38 }
backend/src/test/java/com/xly/erp/module/usr/controller/UserControllerIT.java
@@ -197,6 +197,201 @@ class UserControllerIT { @@ -197,6 +197,201 @@ class UserControllerIT {
197 assertThat(count).isZero(); 197 assertThat(count).isZero();
198 } 198 }
199 199
  200 + @Test
  201 + void putValidBody_with_jwt_returns200_andUpdates() throws Exception {
  202 + Integer staffId = insertStaff("sp_test_pst1", "员工1");
  203 + Integer cat1 = insertCategory("sp_test_pc_p1", "权限1");
  204 + Integer cat2 = insertCategory("sp_test_pc_p2", "权限2");
  205 + Integer userId = insertUserWithPerms("sp_test_u_putorig", "原用户", staffId, cat1);
  206 +
  207 + String token = testJwtHelper.signFor("ADMIN001");
  208 + HttpHeaders headers = jsonHeaders();
  209 + headers.set("Authorization", "Bearer " + token);
  210 + Map<String, Object> body = baseBody("sp_test_u_putorig", "原用户改名");
  211 + body.put("permissionCategoryIds", List.of(cat1, cat2));
  212 +
  213 + ResponseEntity<String> resp = rest.exchange(
  214 + idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);
  215 +
  216 + JsonNode jb = objectMapper.readTree(resp.getBody());
  217 + assertThat(jb.get("code").asInt()).isZero();
  218 + assertThat(jb.get("data").get("iIncrement").asInt()).isEqualTo(userId);
  219 +
  220 + Map<String, Object> row = jdbcTemplate.queryForMap(
  221 + "SELECT sUserName, sPasswordHash, sCreatedBy FROM tUser WHERE iIncrement = ?", userId);
  222 + assertThat(row.get("sUserName")).isEqualTo("原用户改名");
  223 + assertThat((String) row.get("sPasswordHash")).startsWith("$2a$");
  224 + assertThat(row.get("sCreatedBy")).isEqualTo("ORIG_CREATOR");
  225 +
  226 + Integer permCount = jdbcTemplate.queryForObject(
  227 + "SELECT COUNT(1) FROM tUserPermission WHERE iUserId = ?", Integer.class, userId);
  228 + assertThat(permCount).isEqualTo(2);
  229 + }
  230 +
  231 + @Test
  232 + void putNonExistentId_returns40400() throws Exception {
  233 + String token = testJwtHelper.signFor("ADMIN001");
  234 + HttpHeaders headers = jsonHeaders();
  235 + headers.set("Authorization", "Bearer " + token);
  236 + Map<String, Object> body = baseBody("sp_test_u_no", "无");
  237 +
  238 + ResponseEntity<String> resp = rest.exchange(
  239 + idUrl(99999990), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);
  240 +
  241 + assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40400);
  242 + }
  243 +
  244 + @Test
  245 + void putAlreadyDeletedId_returns40400() throws Exception {
  246 + Integer userId = insertUserWithPerms("sp_test_u_deleted", "已删", null, null);
  247 + jdbcTemplate.update("UPDATE tUser SET bDeleted = 1 WHERE iIncrement = ?", userId);
  248 + String token = testJwtHelper.signFor("ADMIN001");
  249 + HttpHeaders headers = jsonHeaders();
  250 + headers.set("Authorization", "Bearer " + token);
  251 +
  252 + ResponseEntity<String> resp = rest.exchange(
  253 + idUrl(userId), HttpMethod.PUT, new HttpEntity<>(baseBody("sp_test_u_deleted", "改"), headers),
  254 + String.class);
  255 +
  256 + assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40400);
  257 + }
  258 +
  259 + @Test
  260 + void putInvalidUserType_returns40001() throws Exception {
  261 + Integer userId = insertUserWithPerms("sp_test_u_pinvtype", "原", null, null);
  262 + String token = testJwtHelper.signFor("ADMIN001");
  263 + HttpHeaders headers = jsonHeaders();
  264 + headers.set("Authorization", "Bearer " + token);
  265 + Map<String, Object> body = baseBody("sp_test_u_pinvtype", "改");
  266 + body.put("sUserType", "火星");
  267 +
  268 + ResponseEntity<String> resp = rest.exchange(
  269 + idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);
  270 +
  271 + assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40001);
  272 + }
  273 +
  274 + @Test
  275 + void putDuplicateUserNo_returns40020() throws Exception {
  276 + Integer u1 = insertUserWithPerms("sp_test_u_pdupA", "AAA", null, null);
  277 + Integer u2 = insertUserWithPerms("sp_test_u_pdupB", "BBB", null, null);
  278 + String token = testJwtHelper.signFor("ADMIN001");
  279 + HttpHeaders headers = jsonHeaders();
  280 + headers.set("Authorization", "Bearer " + token);
  281 + Map<String, Object> body = baseBody("sp_test_u_pdupA", "改成 A");
  282 +
  283 + ResponseEntity<String> resp = rest.exchange(
  284 + idUrl(u2), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);
  285 +
  286 + assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40020);
  287 + }
  288 +
  289 + @Test
  290 + void putStaffNotFound_returns40022() throws Exception {
  291 + Integer userId = insertUserWithPerms("sp_test_u_pstaff", "原", null, null);
  292 + String token = testJwtHelper.signFor("ADMIN001");
  293 + HttpHeaders headers = jsonHeaders();
  294 + headers.set("Authorization", "Bearer " + token);
  295 + Map<String, Object> body = baseBody("sp_test_u_pstaff", "改");
  296 + body.put("iStaffId", 99999990);
  297 +
  298 + ResponseEntity<String> resp = rest.exchange(
  299 + idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);
  300 +
  301 + assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40022);
  302 + }
  303 +
  304 + @Test
  305 + void putPermissionCategoryNotFound_returns40023() throws Exception {
  306 + Integer userId = insertUserWithPerms("sp_test_u_pperm", "原", null, null);
  307 + String token = testJwtHelper.signFor("ADMIN001");
  308 + HttpHeaders headers = jsonHeaders();
  309 + headers.set("Authorization", "Bearer " + token);
  310 + Map<String, Object> body = baseBody("sp_test_u_pperm", "改");
  311 + body.put("permissionCategoryIds", List.of(99999991));
  312 +
  313 + ResponseEntity<String> resp = rest.exchange(
  314 + idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);
  315 +
  316 + assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40023);
  317 + }
  318 +
  319 + @Test
  320 + void putWithEmptyPermissionIds_clearsAssociations() throws Exception {
  321 + Integer cat1 = insertCategory("sp_test_pc_e1", "权限");
  322 + Integer userId = insertUserWithPerms("sp_test_u_pclear", "原", null, cat1);
  323 +
  324 + String token = testJwtHelper.signFor("ADMIN001");
  325 + HttpHeaders headers = jsonHeaders();
  326 + headers.set("Authorization", "Bearer " + token);
  327 + Map<String, Object> body = baseBody("sp_test_u_pclear", "改");
  328 + body.remove("permissionCategoryIds");
  329 +
  330 + ResponseEntity<String> resp = rest.exchange(
  331 + idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);
  332 +
  333 + assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isZero();
  334 + Integer permCount = jdbcTemplate.queryForObject(
  335 + "SELECT COUNT(1) FROM tUserPermission WHERE iUserId = ?", Integer.class, userId);
  336 + assertThat(permCount).isZero();
  337 + String passHash = jdbcTemplate.queryForObject(
  338 + "SELECT sPasswordHash FROM tUser WHERE iIncrement = ?", String.class, userId);
  339 + assertThat(passHash).startsWith("$2a$");
  340 + }
  341 +
  342 + @Test
  343 + void putWithoutJwt_permitAllStub_returns200_andDoesNotChangeCreatedBy() throws Exception {
  344 + Integer userId = insertUserWithPerms("sp_test_u_pnojwt", "原", null, null);
  345 + HttpHeaders headers = jsonHeaders();
  346 + Map<String, Object> body = baseBody("sp_test_u_pnojwt", "改");
  347 +
  348 + ResponseEntity<String> resp = rest.exchange(
  349 + idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);
  350 +
  351 + assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isZero();
  352 + String createdBy = jdbcTemplate.queryForObject(
  353 + "SELECT sCreatedBy FROM tUser WHERE iIncrement = ?", String.class, userId);
  354 + assertThat(createdBy).isEqualTo("ORIG_CREATOR");
  355 + }
  356 +
  357 + @Test
  358 + void putTamperedJwt_returns20001() throws Exception {
  359 + Integer userId = insertUserWithPerms("sp_test_u_ptamper", "原", null, null);
  360 + HttpHeaders headers = jsonHeaders();
  361 + headers.set("Authorization", "Bearer not.a.real.jwt");
  362 + Map<String, Object> body = baseBody("sp_test_u_ptamper", "改");
  363 +
  364 + ResponseEntity<String> resp = rest.exchange(
  365 + idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);
  366 +
  367 + assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(20001);
  368 + String name = jdbcTemplate.queryForObject(
  369 + "SELECT sUserName FROM tUser WHERE iIncrement = ?", String.class, userId);
  370 + assertThat(name).isEqualTo("原");
  371 + }
  372 +
  373 + private String idUrl(Integer id) {
  374 + return "http://localhost:" + port + "/api/usr/users/" + id;
  375 + }
  376 +
  377 + private Integer insertUserWithPerms(String userNo, String userName, Integer staffId, Integer catId) {
  378 + jdbcTemplate.update(
  379 + "INSERT INTO tUser (sBrandsId, sSubsidiaryId, tCreateDate, sUserNo, sUserName, iStaffId, "
  380 + + "sUserType, sLanguage, bCanModifyDocs, sPasswordHash, sCreatedBy, bDeleted) "
  381 + + "VALUES ('XLY','XLY', NOW(), ?, ?, ?, '普通用户', 'zh', 0, "
  382 + + "'$2a$10$origHashOrigHashOrigHashOrigHashOrigHashOrigHashOrig', 'ORIG_CREATOR', 0)",
  383 + userNo, userName, staffId);
  384 + Integer userId = jdbcTemplate.queryForObject(
  385 + "SELECT iIncrement FROM tUser WHERE sUserNo = ?", Integer.class, userNo);
  386 + if (catId != null) {
  387 + jdbcTemplate.update(
  388 + "INSERT INTO tUserPermission (sBrandsId, sSubsidiaryId, tCreateDate, iUserId, iCategoryId, sCreatedBy) "
  389 + + "VALUES ('XLY','XLY', NOW(), ?, ?, 'ORIG_CREATOR')",
  390 + userId, catId);
  391 + }
  392 + return userId;
  393 + }
  394 +
200 private Integer insertStaff(String staffNo, String name) { 395 private Integer insertStaff(String staffNo, String name) {
201 jdbcTemplate.update( 396 jdbcTemplate.update(
202 "INSERT INTO tStaff (sBrandsId, sSubsidiaryId, tCreateDate, sStaffNo, sStaffName, sCreatedBy, bDeleted) " 397 "INSERT INTO tStaff (sBrandsId, sSubsidiaryId, tCreateDate, sStaffNo, sStaffName, sCreatedBy, bDeleted) "