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.
137 lines
6.5 KiB
137 lines
6.5 KiB
package com.mydreamjob.talentdiscovery;
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import com.mydreamjob.auth.JwtTokenProvider;
|
|
import com.mydreamjob.common.exception.BusinessException;
|
|
import com.mydreamjob.common.exception.ErrorCode;
|
|
import com.mydreamjob.talentdiscovery.dto.TalentDiscoveryCandidateResponse;
|
|
import com.mydreamjob.talentdiscovery.dto.TalentDiscoveryPageResponse;
|
|
import com.mydreamjob.talentdiscovery.dto.TalentDiscoveryPreferenceResponse;
|
|
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.http.MediaType;
|
|
import org.springframework.test.context.ActiveProfiles;
|
|
import org.springframework.test.context.TestPropertySource;
|
|
import org.springframework.test.web.servlet.MockMvc;
|
|
|
|
import java.util.List;
|
|
|
|
import static org.hamcrest.Matchers.containsString;
|
|
import static org.hamcrest.Matchers.not;
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.anyInt;
|
|
import static org.mockito.ArgumentMatchers.anyLong;
|
|
import static org.mockito.Mockito.doThrow;
|
|
import static org.mockito.Mockito.when;
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
|
|
|
@SpringBootTest
|
|
@AutoConfigureMockMvc
|
|
@ActiveProfiles("integration-test")
|
|
@TestPropertySource(properties = "spring.jpa.open-in-view=false")
|
|
class TalentDiscoveryControllerTest {
|
|
|
|
@Autowired private MockMvc mockMvc;
|
|
@Autowired private JwtTokenProvider jwtTokenProvider;
|
|
@MockBean private TalentDiscoveryService service;
|
|
@MockBean private RedisTemplate<String, Object> redisTemplate;
|
|
|
|
private final ObjectMapper mapper = new ObjectMapper();
|
|
|
|
@BeforeEach
|
|
@SuppressWarnings("unchecked")
|
|
void setUp() {
|
|
ValueOperations<String, Object> ops = org.mockito.Mockito.mock(ValueOperations.class);
|
|
when(redisTemplate.opsForValue()).thenReturn(ops);
|
|
when(redisTemplate.hasKey(any())).thenReturn(false);
|
|
}
|
|
|
|
private String token(long userId, String role) {
|
|
return com.mydreamjob.auth.support.TestAuthTokens.bearer(userId, role);
|
|
}
|
|
|
|
@Test
|
|
void getPreference_usesJwtIdentityAndReturnsPreference() throws Exception {
|
|
when(service.getPreference(100L)).thenReturn(TalentDiscoveryPreferenceResponse.builder()
|
|
.enabled(false).version(0L).build());
|
|
|
|
mockMvc.perform(get("/profile/me/talent-discovery")
|
|
.header("Authorization", token(100L, "STUDENT")))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.code").value(200))
|
|
.andExpect(jsonPath("$.data.enabled").value(false))
|
|
.andExpect(jsonPath("$.data.version").value(0));
|
|
}
|
|
|
|
@Test
|
|
void getPreference_withoutTokenReturns401() throws Exception {
|
|
mockMvc.perform(get("/profile/me/talent-discovery"))
|
|
.andExpect(status().isUnauthorized())
|
|
.andExpect(jsonPath("$.code").value(401));
|
|
}
|
|
|
|
@Test
|
|
void updatePreference_studentCannotSupplyIdentityAndReturns200() throws Exception {
|
|
when(service.updatePreference(anyLong(), any(), any())).thenReturn(
|
|
TalentDiscoveryPreferenceResponse.builder().enabled(true).version(1L).build());
|
|
|
|
String body = mapper.writeValueAsString(java.util.Map.of(
|
|
"enabled", true, "expectedVersion", 0, "studentUserId", 999999));
|
|
mockMvc.perform(put("/profile/me/talent-discovery")
|
|
.header("Authorization", token(100L, "STUDENT"))
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.content(body))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.code").value(200))
|
|
.andExpect(jsonPath("$.data.enabled").value(true));
|
|
}
|
|
|
|
@Test
|
|
void companyRecommendationResponseContainsOnlyWhitelistedCardFields() throws Exception {
|
|
TalentDiscoveryCandidateResponse candidate = TalentDiscoveryCandidateResponse.builder()
|
|
.candidateKey("opaque-key")
|
|
.candidateLabel("开放人才候选人")
|
|
.city("杭州")
|
|
.education("本科")
|
|
.graduationYear(2026)
|
|
.skills(List.of("Java", "Spring Boot"))
|
|
.fitBand("HIGH")
|
|
.summary("岗位画像与候选人公开资料存在较高匹配度")
|
|
.signalsAvailable(List.of("PREFERENCE", "RIASEC", "ABILITY"))
|
|
.build();
|
|
when(service.recommendations(anyLong(), anyLong(), anyInt(), anyInt())).thenReturn(
|
|
TalentDiscoveryPageResponse.builder().mode("PERSONALIZED")
|
|
.items(List.of(candidate)).total(1).page(0).size(20).totalPages(1).build());
|
|
|
|
mockMvc.perform(get("/companies/me/jobs/9/talent-recommendations")
|
|
.header("Authorization", token(200L, "COMPANY")))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.data.items[0].candidateKey").value("opaque-key"))
|
|
.andExpect(jsonPath("$.data.items[0].fitScore").doesNotExist())
|
|
.andExpect(content().string(not(containsString("studentUserId"))))
|
|
.andExpect(content().string(not(containsString("dimensionScores"))))
|
|
.andExpect(content().string(not(containsString("overallScore"))))
|
|
.andExpect(content().string(not(containsString("fitScore"))));
|
|
}
|
|
|
|
@Test
|
|
void companyRecommendationServiceForbiddenIsMappedTo403() throws Exception {
|
|
doThrow(new BusinessException(ErrorCode.FORBIDDEN))
|
|
.when(service).recommendations(anyLong(), anyLong(), anyInt(), anyInt());
|
|
|
|
mockMvc.perform(get("/companies/me/jobs/9/talent-recommendations")
|
|
.header("Authorization", token(201L, "COMPANY")))
|
|
.andExpect(status().isForbidden())
|
|
.andExpect(jsonPath("$.code").value(2002));
|
|
}
|
|
}
|
|
|