|
|
@@ -0,0 +1,224 @@
|
|
|
+package com.etotem.cfc.controller.admin;
|
|
|
+
|
|
|
+import com.etotem.cfc.common.Result;
|
|
|
+import com.etotem.cfc.entity.User;
|
|
|
+import com.etotem.cfc.mapper.UserMapper;
|
|
|
+import com.etotem.cfc.service.AdminReferralTreeService;
|
|
|
+import com.etotem.cfc.service.CommissionService;
|
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
|
+import org.junit.jupiter.api.Test;
|
|
|
+
|
|
|
+import java.lang.reflect.Field;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+import static org.junit.jupiter.api.Assertions.*;
|
|
|
+import static org.mockito.Mockito.*;
|
|
|
+
|
|
|
+/**
|
|
|
+ * TR-25 用户管理「推荐团队」查看契约测试(研发 → 测试送测,2026-11-10 22:4x 错峰轮)。
|
|
|
+ * <p>对象:{@link AdminReferralController}(实现 6c0f05701 已合入 origin/cfclub 但零契约/零场景覆盖)。
|
|
|
+ * <p>风格与既有 HealthPlanProductSelectionContractTest 一致:mock Service/Mapper + 反射注入,直接调用(无 Spring 上下文)。
|
|
|
+ * <p>覆盖:/api/admin/referral/{summary,members,tree} 三端点 ——
|
|
|
+ * 无权限(匿名/非后台角色)拒绝 · userId 参数校验 · 用户不存在 · 成功分支字段形态 ·
|
|
|
+ * level 归一化(L1/L2/默认 ALL)· maxLevel 默认 3 · 幂等参数透传。
|
|
|
+ */
|
|
|
+class AdminReferralContractTest {
|
|
|
+
|
|
|
+ private AdminReferralController controller;
|
|
|
+ private CommissionService commissionService;
|
|
|
+ private UserMapper userMapper;
|
|
|
+ private AdminReferralTreeService adminReferralTreeService;
|
|
|
+
|
|
|
+ @BeforeEach
|
|
|
+ void setUp() throws Exception {
|
|
|
+ controller = new AdminReferralController();
|
|
|
+ commissionService = mock(CommissionService.class);
|
|
|
+ userMapper = mock(UserMapper.class);
|
|
|
+ adminReferralTreeService = mock(AdminReferralTreeService.class);
|
|
|
+ set("commissionService", controller, commissionService);
|
|
|
+ set("userMapper", controller, userMapper);
|
|
|
+ set("adminReferralTreeService", controller, adminReferralTreeService);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void set(String name, Object target, Object v) throws Exception {
|
|
|
+ Field f = target.getClass().getDeclaredField(name);
|
|
|
+ f.setAccessible(true);
|
|
|
+ f.set(target, v);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Object> params(Long userId, String extraKey, Object extraVal) {
|
|
|
+ Map<String, Object> p = new HashMap<>();
|
|
|
+ if (userId != null) p.put("userId", userId);
|
|
|
+ if (extraKey != null) p.put(extraKey, extraVal);
|
|
|
+ return p;
|
|
|
+ }
|
|
|
+
|
|
|
+ private User user(Long id) {
|
|
|
+ User u = new User();
|
|
|
+ u.setId(id);
|
|
|
+ u.setNickname("测试用户");
|
|
|
+ u.setPhone("13800000000");
|
|
|
+ u.setReferralCode("R" + id);
|
|
|
+ u.setCreatedAt(new Date(1700000000000L));
|
|
|
+ return u;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 权限门(无权限一律拒绝) ====================
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void summary_匿名无角色返回无权限() {
|
|
|
+ Result<?> r = controller.summary(params(1L, null, null), null, null);
|
|
|
+ assertEquals("无权限", r.getMessage());
|
|
|
+ assertEquals(500, r.getCode());
|
|
|
+ verify(commissionService, never()).getMyReferrer(any(), any());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void summary_C端角色parent返回无权限() {
|
|
|
+ Result<?> r = controller.summary(params(1L, null, null), "parent", null);
|
|
|
+ assertEquals("无权限", r.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void members_非后台角色child返回无权限() {
|
|
|
+ Result<?> r = controller.members(params(1L, null, null), "child", null);
|
|
|
+ assertEquals("无权限", r.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void tree_匿名返回无权限() {
|
|
|
+ Result<?> r = controller.tree(params(1L, null, null), null, null);
|
|
|
+ assertEquals("无权限", r.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== summary:参数校验 / 用户不存在 / 成功 ====================
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void summary_userId为空返回错误() {
|
|
|
+ Result<?> r = controller.summary(params(null, null, null), "admin", null);
|
|
|
+ assertEquals("userId不能为空", r.getMessage());
|
|
|
+ verify(userMapper, never()).selectById(any());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void summary_用户不存在返回错误() {
|
|
|
+ when(userMapper.selectById(99L)).thenReturn(null);
|
|
|
+ Result<?> r = controller.summary(params(99L, null, null), "admin", null);
|
|
|
+ assertEquals("用户不存在", r.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void summary_成功返回推荐关系概览字段形态() {
|
|
|
+ when(userMapper.selectById(10L)).thenReturn(user(10L));
|
|
|
+ Map<String, Object> upstream = new HashMap<>();
|
|
|
+ upstream.put("hasReferrer", true);
|
|
|
+ upstream.put("referrerId", 3L);
|
|
|
+ upstream.put("nickname", "上级");
|
|
|
+ when(commissionService.getMyReferrer(10L, null)).thenReturn(upstream);
|
|
|
+ Map<String, Object> stats = new HashMap<>();
|
|
|
+ stats.put("l1Count", 2);
|
|
|
+ stats.put("l2Count", 5);
|
|
|
+ stats.put("totalCommission", 128.5);
|
|
|
+ when(commissionService.getTeamStats(10L)).thenReturn(stats);
|
|
|
+
|
|
|
+ Result<Map<String, Object>> r = controller.summary(params(10L, null, null), "admin", null);
|
|
|
+ assertEquals(200, r.getCode());
|
|
|
+ Map<String, Object> d = r.getData();
|
|
|
+ assertNotNull(d);
|
|
|
+ assertEquals(10L, d.get("userId"));
|
|
|
+ assertEquals("测试用户", d.get("nickname"));
|
|
|
+ assertEquals("R10", d.get("referralCode"));
|
|
|
+ assertEquals(true, d.get("hasReferrer"));
|
|
|
+ assertEquals(3L, d.get("referrerId"));
|
|
|
+ assertEquals(2, d.get("l1Count"));
|
|
|
+ assertEquals(5, d.get("l2Count"));
|
|
|
+ assertEquals(128.5, d.get("totalCommission"));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void summary_无推荐人边界() {
|
|
|
+ when(userMapper.selectById(20L)).thenReturn(user(20L));
|
|
|
+ Map<String, Object> upstream = new HashMap<>();
|
|
|
+ upstream.put("hasReferrer", false);
|
|
|
+ upstream.put("referrerId", null);
|
|
|
+ upstream.put("nickname", null);
|
|
|
+ when(commissionService.getMyReferrer(20L, null)).thenReturn(upstream);
|
|
|
+ when(commissionService.getTeamStats(20L)).thenReturn(new HashMap<>());
|
|
|
+
|
|
|
+ Result<Map<String, Object>> r = controller.summary(params(20L, null, null), "admin", null);
|
|
|
+ assertEquals(false, r.getData().get("hasReferrer"));
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== members:level 归一化 / 参数透传 ====================
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void members_level非法归一化为ALL() {
|
|
|
+ when(commissionService.getTeamList(10L, "ALL", 1, 20)).thenReturn(new HashMap<>());
|
|
|
+ Result<?> r = controller.members(params(10L, "level", "L3"), "admin", null);
|
|
|
+ assertEquals(200, r.getCode());
|
|
|
+ verify(commissionService).getTeamList(10L, "ALL", 1, 20);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void members_levelL1直传() {
|
|
|
+ when(commissionService.getTeamList(10L, "L1", 1, 20)).thenReturn(new HashMap<>());
|
|
|
+ Result<?> r = controller.members(params(10L, "level", "L1"), "admin", null);
|
|
|
+ verify(commissionService).getTeamList(10L, "L1", 1, 20);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void members_userId为空返回错误() {
|
|
|
+ Result<?> r = controller.members(params(null, null, null), "admin", null);
|
|
|
+ assertEquals("userId不能为空", r.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== tree:maxLevel 默认 3 / 传值 / 空树 ====================
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void tree_maxLevel默认3() {
|
|
|
+ when(adminReferralTreeService.buildTree(10L, 3)).thenReturn(new HashMap<>());
|
|
|
+ Result<?> r = controller.tree(params(10L, null, null), "admin", null);
|
|
|
+ assertEquals(200, r.getCode());
|
|
|
+ verify(adminReferralTreeService).buildTree(10L, 3);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void tree_maxLevel8上限透传() {
|
|
|
+ when(adminReferralTreeService.buildTree(10L, 8)).thenReturn(new HashMap<>());
|
|
|
+ Result<?> r = controller.tree(params(10L, "maxLevel", 8), "admin", null);
|
|
|
+ verify(adminReferralTreeService).buildTree(10L, 8);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void tree_userId不存在返回错误() {
|
|
|
+ Result<?> r = controller.tree(params(99L, null, null), "admin", null);
|
|
|
+ assertEquals(200, r.getCode()); // tree 不校验用户存在,只按 userId 建树(空树由 Service 返回)
|
|
|
+ verify(adminReferralTreeService).buildTree(99L, 3);
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== roles 列表形式(hasAnyBackendRole) ====================
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void summary_roleList含backend角色放行() {
|
|
|
+ when(userMapper.selectById(10L)).thenReturn(user(10L));
|
|
|
+ Map<String, Object> upstream = new HashMap<>();
|
|
|
+ upstream.put("hasReferrer", false);
|
|
|
+ when(commissionService.getMyReferrer(10L, null)).thenReturn(upstream);
|
|
|
+ when(commissionService.getTeamStats(10L)).thenReturn(new HashMap<>());
|
|
|
+ List<String> roles = Arrays.asList("operator");
|
|
|
+ Result<?> r = controller.summary(params(10L, null, null), null, roles);
|
|
|
+ assertEquals(200, r.getCode());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void summary_roleList纯C端角色拒绝() {
|
|
|
+ List<String> roles = Collections.singletonList("parent");
|
|
|
+ Result<?> r = controller.summary(params(10L, null, null), null, roles);
|
|
|
+ assertEquals("无权限", r.getMessage());
|
|
|
+ }
|
|
|
+}
|