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.
 
 
 

120 lines
5.9 KiB

package com.mydreamjob.messaging;
import com.mydreamjob.common.exception.BusinessException;
import com.mydreamjob.common.exception.ErrorCode;
import com.mydreamjob.messaging.dto.CreateConversationRequest;
import com.mydreamjob.messaging.dto.MessagePageResponse;
import com.mydreamjob.messaging.dto.SendMessageRequest;
import com.fasterxml.jackson.databind.ObjectMapper;
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.web.servlet.MockMvc;
import java.util.List;
import java.util.Map;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("integration-test")
class MessagingControllerTest {
@Autowired private MockMvc mockMvc;
@Autowired private com.mydreamjob.auth.JwtTokenProvider jwtTokenProvider;
@MockBean private MessagingService messagingService;
@MockBean private RedisTemplate<String, Object> redisTemplate;
private final ObjectMapper mapper = new ObjectMapper();
@BeforeEach
@SuppressWarnings("unchecked")
void setUp() {
ValueOperations<String, Object> ops = mock(ValueOperations.class);
when(redisTemplate.opsForValue()).thenReturn(ops);
when(redisTemplate.hasKey(any())).thenReturn(false);
}
private String token() {
return "Bearer " + jwtTokenProvider.generateAccessToken(100L, "1", Map.of("roles", "STUDENT"));
}
@Test void listConversations_shouldReturn200() throws Exception {
when(messagingService.listConversations(100L)).thenReturn(List.of());
mockMvc.perform(get("/conversations").header("Authorization", token()))
.andExpect(status().isOk()).andExpect(jsonPath("$.code").value(200));
}
@Test void getConversation_shouldReturn200() throws Exception {
when(messagingService.getConversation(1L, 100L)).thenReturn(Map.of("id", 1, "type", "DIRECT"));
mockMvc.perform(get("/conversations/1").header("Authorization", token()))
.andExpect(status().isOk()).andExpect(jsonPath("$.data.id").value(1));
}
@Test void createConversation_shouldReturn200() throws Exception {
CreateConversationRequest req = new CreateConversationRequest();
req.setParticipantUserId(200L);
when(messagingService.createOrGetDirectConversation(eq(100L), any()))
.thenReturn(Map.of("id", 2, "type", "DIRECT"));
mockMvc.perform(post("/conversations").header("Authorization", token())
.contentType(MediaType.APPLICATION_JSON).content(mapper.writeValueAsString(req)))
.andExpect(status().isOk()).andExpect(jsonPath("$.data.id").value(2));
}
@Test void sendMessage_shouldReturn200() throws Exception {
SendMessageRequest req = new SendMessageRequest();
req.setConversationId(1L); req.setContent("Hello");
when(messagingService.sendMessage(eq(100L), any())).thenReturn(Map.of("id", 1, "content", "Hello"));
mockMvc.perform(post("/conversations/messages").header("Authorization", token())
.contentType(MediaType.APPLICATION_JSON).content(mapper.writeValueAsString(req)))
.andExpect(status().isOk()).andExpect(jsonPath("$.data.content").value("Hello"));
}
@Test void listMessages_shouldReturn200() throws Exception {
when(messagingService.listMessages(eq(1L), eq(100L), eq(0), eq(20)))
.thenReturn(MessagePageResponse.builder().items(List.of()).total(0).page(0).size(20).totalPages(0).build());
mockMvc.perform(get("/conversations/1/messages").header("Authorization", token()))
.andExpect(status().isOk()).andExpect(jsonPath("$.code").value(200));
}
@Test void markRead_shouldReturn200() throws Exception {
doNothing().when(messagingService).markRead(1L, 100L);
mockMvc.perform(post("/conversations/1/read").header("Authorization", token()))
.andExpect(status().isOk()).andExpect(jsonPath("$.code").value(200));
}
@Test void createConversation_noToken_shouldReturn401() throws Exception {
String body = mapper.writeValueAsString(Map.of("participantUserId", 200));
mockMvc.perform(post("/conversations").contentType(MediaType.APPLICATION_JSON).content(body))
.andExpect(status().isUnauthorized());
}
// ── 会话不存在 → 404/8305;非成员 → 403/2002 ────────────────
@Test void getConversation_notFound_shouldReturn404() throws Exception {
when(messagingService.getConversation(1L, 100L))
.thenThrow(new BusinessException(ErrorCode.CONVERSATION_NOT_FOUND));
mockMvc.perform(get("/conversations/1").header("Authorization", token()))
.andExpect(status().isNotFound())
.andExpect(jsonPath("$.code").value(8305));
}
@Test void getConversation_asNonMember_shouldReturn403() throws Exception {
when(messagingService.getConversation(1L, 100L))
.thenThrow(new BusinessException(ErrorCode.FORBIDDEN));
mockMvc.perform(get("/conversations/1").header("Authorization", token()))
.andExpect(status().isForbidden())
.andExpect(jsonPath("$.code").value(2002));
}
}