You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
6.1 KiB
136 lines
6.1 KiB
package com.mydreamjob.resume;
|
|
|
|
import com.mydreamjob.auth.User;
|
|
import com.mydreamjob.auth.UserRepository;
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
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.mock.mockito.MockBean;
|
|
import org.springframework.data.redis.core.RedisTemplate;
|
|
import org.springframework.data.redis.core.ValueOperations;
|
|
import org.springframework.mock.web.MockMultipartFile;
|
|
import org.springframework.test.context.ActiveProfiles;
|
|
import org.springframework.test.web.servlet.MockMvc;
|
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
|
|
|
import java.util.Map;
|
|
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.Mockito.mock;
|
|
import static org.mockito.Mockito.when;
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
|
|
|
/**
|
|
* 简历版本权限一致性集成测试(真实 Service + 真实 H2)。
|
|
*
|
|
* <p>版本存在但属于他人 → 四个接口一律 HTTP 403;版本不存在 → 404。
|
|
* 覆盖:GET/PUT/DELETE /profile/me/resume-versions/{id} 与 POST .../default。
|
|
*/
|
|
@SpringBootTest
|
|
@AutoConfigureMockMvc
|
|
@ActiveProfiles("integration-test")
|
|
class ResumeVersionPermissionControllerTest {
|
|
|
|
@Autowired private MockMvc mockMvc;
|
|
@Autowired private com.mydreamjob.auth.JwtTokenProvider jwtTokenProvider;
|
|
@Autowired private ResumeVersionService resumeVersionService;
|
|
@Autowired private UserRepository userRepository;
|
|
|
|
@MockBean private RedisTemplate<String, Object> redisTemplate;
|
|
|
|
private Long ownerUserId;
|
|
private Long otherUserId;
|
|
private Long versionId;
|
|
|
|
private static final java.util.concurrent.atomic.AtomicLong PHONE_SEQ =
|
|
new java.util.concurrent.atomic.AtomicLong(300);
|
|
|
|
@BeforeEach
|
|
@SuppressWarnings("unchecked")
|
|
void setUp() {
|
|
ValueOperations<String, Object> ops = mock(ValueOperations.class);
|
|
when(redisTemplate.opsForValue()).thenReturn(ops);
|
|
when(redisTemplate.hasKey(any())).thenReturn(false);
|
|
|
|
ownerUserId = createStudent();
|
|
otherUserId = createStudent();
|
|
MockMultipartFile file = new MockMultipartFile("file", "r.pdf", "application/pdf",
|
|
"%PDF-1.7\npermission-fixture\n%%EOF\n".getBytes(java.nio.charset.StandardCharsets.US_ASCII));
|
|
ResumeVersion version = resumeVersionService.createVersion(ownerUserId, "秋招版", file);
|
|
versionId = version.getId();
|
|
}
|
|
|
|
private Long createStudent() {
|
|
User u = userRepository.save(User.builder()
|
|
.phone("177" + String.format("%08d", PHONE_SEQ.incrementAndGet()))
|
|
.nickname("候选人").role(User.Role.STUDENT).active(true).verified(true).build());
|
|
return u.getId();
|
|
}
|
|
|
|
private String token(Long userId) {
|
|
return com.mydreamjob.auth.support.TestAuthTokens.bearer(userId, "STUDENT");
|
|
}
|
|
|
|
// ── 另一学生访问 → 403 ────────────────────────────────────
|
|
|
|
@Test
|
|
void get_otherStudent_shouldReturn403() throws Exception {
|
|
mockMvc.perform(get("/profile/me/resume-versions/" + versionId)
|
|
.header("Authorization", token(otherUserId)))
|
|
.andExpect(status().isForbidden())
|
|
.andExpect(jsonPath("$.code").value(com.mydreamjob.common.exception.ErrorCode.FORBIDDEN.getCode()));
|
|
}
|
|
|
|
@Test
|
|
void update_otherStudent_shouldReturn403() throws Exception {
|
|
mockMvc.perform(MockMvcRequestBuilders.multipart("/profile/me/resume-versions/" + versionId)
|
|
.param("name", "改他人")
|
|
.with(req -> {
|
|
req.setMethod("PUT");
|
|
return req;
|
|
})
|
|
.header("Authorization", token(otherUserId)))
|
|
.andExpect(status().isForbidden())
|
|
.andExpect(jsonPath("$.code").value(com.mydreamjob.common.exception.ErrorCode.FORBIDDEN.getCode()));
|
|
}
|
|
|
|
@Test
|
|
void delete_otherStudent_shouldReturn403() throws Exception {
|
|
mockMvc.perform(delete("/profile/me/resume-versions/" + versionId)
|
|
.header("Authorization", token(otherUserId)))
|
|
.andExpect(status().isForbidden())
|
|
.andExpect(jsonPath("$.code").value(com.mydreamjob.common.exception.ErrorCode.FORBIDDEN.getCode()));
|
|
}
|
|
|
|
@Test
|
|
void setDefault_otherStudent_shouldReturn403() throws Exception {
|
|
mockMvc.perform(post("/profile/me/resume-versions/" + versionId + "/default")
|
|
.header("Authorization", token(otherUserId)))
|
|
.andExpect(status().isForbidden())
|
|
.andExpect(jsonPath("$.code").value(com.mydreamjob.common.exception.ErrorCode.FORBIDDEN.getCode()));
|
|
}
|
|
|
|
// ── 不存在 → 404 ──────────────────────────────────────────
|
|
|
|
@Test
|
|
void get_notExist_shouldReturn404() throws Exception {
|
|
mockMvc.perform(get("/profile/me/resume-versions/999999")
|
|
.header("Authorization", token(otherUserId)))
|
|
.andExpect(status().isNotFound())
|
|
.andExpect(jsonPath("$.code").value(com.mydreamjob.common.exception.ErrorCode.RESUME_VERSION_NOT_FOUND.getCode()));
|
|
}
|
|
|
|
// ── 本人 → 200(基线,确认规则未误伤本人) ─────────────────
|
|
|
|
@Test
|
|
void get_owner_shouldReturn200() throws Exception {
|
|
mockMvc.perform(get("/profile/me/resume-versions/" + versionId)
|
|
.header("Authorization", token(ownerUserId)))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.code").value(200))
|
|
.andExpect(jsonPath("$.data.id").value(versionId));
|
|
}
|
|
}
|
|
|