|
|
@@ -0,0 +1,147 @@
|
|
|
+package com.etotem.cfc.controller.family;
|
|
|
+
|
|
|
+import com.etotem.cfc.dto.FamilyMemberVO;
|
|
|
+import com.etotem.cfc.mapper.UserMapper;
|
|
|
+import com.etotem.cfc.service.FamilyMemberService;
|
|
|
+import com.etotem.cfc.service.UnlockGateService;
|
|
|
+import com.etotem.cfc.service.UserService;
|
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
|
+import org.junit.jupiter.api.Test;
|
|
|
+import org.mockito.Mock;
|
|
|
+import org.mockito.MockitoAnnotations;
|
|
|
+import org.springframework.http.MediaType;
|
|
|
+import org.springframework.test.util.ReflectionTestUtils;
|
|
|
+import org.springframework.test.web.servlet.MockMvc;
|
|
|
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
|
|
+
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Collections;
|
|
|
+
|
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
|
+import static org.mockito.ArgumentMatchers.anyLong;
|
|
|
+import static org.mockito.Mockito.*;
|
|
|
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
|
|
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
|
|
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
|
|
+
|
|
|
+/**
|
|
|
+ * B2-1:family/member/list 支持 params.familyId + 行级隔离 + 删除 ensureUserFamily 兜底建家庭。
|
|
|
+ *
|
|
|
+ * 契约:
|
|
|
+ * - 传 familyId 且调用者在有效家庭集内(own family / teacher_family_ids / guide_families 绑定)→ 返回该家庭全部成员
|
|
|
+ * - 传 familyId 但调用者无权(platform 角色除外)→ Result code=403
|
|
|
+ * - 平台角色(admin/operator/finance)传任意 familyId → 放行
|
|
|
+ * - 不传 familyId → 返回本人家庭成员;绝不静默调用 ensureUserFamily 建家庭
|
|
|
+ */
|
|
|
+public class FamilyMembersControllerListTest {
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ private FamilyMemberService familyMemberService;
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ private UserService userService;
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ private UnlockGateService unlockGateService;
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ private UserMapper userMapper;
|
|
|
+
|
|
|
+ private MockMvc mockMvc;
|
|
|
+
|
|
|
+ @BeforeEach
|
|
|
+ public void setUp() {
|
|
|
+ MockitoAnnotations.openMocks(this);
|
|
|
+ FamilyMembersController controller = new FamilyMembersController();
|
|
|
+ ReflectionTestUtils.setField(controller, "familyMemberService", familyMemberService);
|
|
|
+ ReflectionTestUtils.setField(controller, "unlockGateService", unlockGateService);
|
|
|
+ ReflectionTestUtils.setField(controller, "userService", userService);
|
|
|
+ ReflectionTestUtils.setField(controller, "userMapper", userMapper);
|
|
|
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void listMembers_withFamilyId_andAccess_returnsMembersOfThatFamily() throws Exception {
|
|
|
+ Long userId = 1L;
|
|
|
+ Long familyId = 5L;
|
|
|
+ when(userService.getEffectiveFamilyIds(userId)).thenReturn(Collections.singleton(familyId));
|
|
|
+ FamilyMemberVO vo = new FamilyMemberVO();
|
|
|
+ vo.setId(11L);
|
|
|
+ when(familyMemberService.listMembersOfFamily(familyId, userId)).thenReturn(Arrays.asList(vo));
|
|
|
+
|
|
|
+ mockMvc.perform(post("/api/family/member/list")
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .content("{\"familyId\":5}")
|
|
|
+ .requestAttr("userId", userId)
|
|
|
+ .requestAttr("role", "teacher")
|
|
|
+ .requestAttr("roles", Collections.singletonList("teacher")))
|
|
|
+ .andExpect(status().isOk())
|
|
|
+ .andExpect(jsonPath("$.code").value(200))
|
|
|
+ .andExpect(jsonPath("$.data[0].id").value(11));
|
|
|
+
|
|
|
+ verify(familyMemberService).listMembersOfFamily(familyId, userId);
|
|
|
+ verify(userService, never()).ensureUserFamily(any());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void listMembers_withFamilyId_noAccess_returns403() throws Exception {
|
|
|
+ Long userId = 1L;
|
|
|
+ Long targetFamilyId = 99L;
|
|
|
+ when(userService.getEffectiveFamilyIds(userId)).thenReturn(Collections.singleton(5L));
|
|
|
+
|
|
|
+ mockMvc.perform(post("/api/family/member/list")
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .content("{\"familyId\":99}")
|
|
|
+ .requestAttr("userId", userId)
|
|
|
+ .requestAttr("role", "teacher")
|
|
|
+ .requestAttr("roles", Collections.singletonList("teacher")))
|
|
|
+ .andExpect(status().isOk())
|
|
|
+ .andExpect(jsonPath("$.code").value(403))
|
|
|
+ .andExpect(jsonPath("$.message").value("无权访问该家庭数据"));
|
|
|
+
|
|
|
+ verify(familyMemberService, never()).listMembersOfFamily(anyLong(), anyLong());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void listMembers_withPlatformRole_anyFamilyAllowed() throws Exception {
|
|
|
+ Long userId = 1L;
|
|
|
+ Long familyId = 999L;
|
|
|
+ FamilyMemberVO vo = new FamilyMemberVO();
|
|
|
+ vo.setId(22L);
|
|
|
+ when(familyMemberService.listMembersOfFamily(familyId, userId)).thenReturn(Arrays.asList(vo));
|
|
|
+
|
|
|
+ mockMvc.perform(post("/api/family/member/list")
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .content("{\"familyId\":999}")
|
|
|
+ .requestAttr("userId", userId)
|
|
|
+ .requestAttr("role", "admin")
|
|
|
+ .requestAttr("roles", Collections.singletonList("admin")))
|
|
|
+ .andExpect(status().isOk())
|
|
|
+ .andExpect(jsonPath("$.code").value(200))
|
|
|
+ .andExpect(jsonPath("$.data[0].id").value(22));
|
|
|
+
|
|
|
+ verify(familyMemberService).listMembersOfFamily(familyId, userId);
|
|
|
+ verify(userService, never()).getEffectiveFamilyIds(any());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void listMembers_withoutFamilyId_usesOwnList_noAutoCreate() throws Exception {
|
|
|
+ Long userId = 1L;
|
|
|
+ FamilyMemberVO vo = new FamilyMemberVO();
|
|
|
+ vo.setId(33L);
|
|
|
+ when(familyMemberService.listMembers(userId)).thenReturn(Arrays.asList(vo));
|
|
|
+
|
|
|
+ mockMvc.perform(post("/api/family/member/list")
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .content("{}")
|
|
|
+ .requestAttr("userId", userId)
|
|
|
+ .requestAttr("role", "parent")
|
|
|
+ .requestAttr("roles", Collections.singletonList("parent")))
|
|
|
+ .andExpect(status().isOk())
|
|
|
+ .andExpect(jsonPath("$.code").value(200))
|
|
|
+ .andExpect(jsonPath("$.data[0].id").value(33));
|
|
|
+
|
|
|
+ verify(familyMemberService).listMembers(userId);
|
|
|
+ verify(userService, never()).ensureUserFamily(any());
|
|
|
+ }
|
|
|
+}
|