Преглед на файлове

test(backend): WorkspaceServiceTest 真正跨主管隔离断言

wangkangyjy преди 1 седмица
родител
ревизия
83c062343c
променени са 1 файла, в които са добавени 57 реда и са изтрити 23 реда
  1. 57 23
      backend/src/test/java/com/yimeng/okr/service/WorkspaceServiceTest.java

+ 57 - 23
backend/src/test/java/com/yimeng/okr/service/WorkspaceServiceTest.java

@@ -14,7 +14,6 @@ import org.mockito.junit.jupiter.MockitoSettings;
 import org.mockito.quality.Strictness;
 import org.springframework.jdbc.core.JdbcTemplate;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -42,38 +41,73 @@ class WorkspaceServiceTest {
         lenient().when(periodMapper.selectById(1L)).thenReturn(period);
         lenient().when(periodMapper.selectList(any()))
                 .thenReturn(List.of(period));
+        // Prevent NPE from buildTodos / buildTeamSummary queryForObject calls
+        lenient().when(jdbcTemplate.queryForObject(anyString(), eq(Integer.class), any(), any()))
+                .thenReturn(0);
+        lenient().when(jdbcTemplate.queryForObject(anyString(), eq(Integer.class), any()))
+                .thenReturn(0);
     }
 
     @Test
-    void buildRisksFiltersByUserId() {
-        // One blocked KR for the user's team
-        Map<String, Object> blockedKr = new HashMap<>();
-        blockedKr.put("title", "Blocked KR");
-        blockedKr.put("real_name", "Subordinate A");
-        List<Map<String, Object>> blockedList = new ArrayList<>();
-        blockedList.add(blockedKr);
-
-        // Mock: blocked KRs returned for the query parameters
-        lenient().when(jdbcTemplate.queryForList(
-                contains("SELECT k.title, u.real_name FROM kr_key_result"),
-                eq(1L), eq(2L), eq(2L)))
-                .thenReturn((List) blockedList);
-        // Default: empty for other queries
-        lenient().when(jdbcTemplate.queryForList(anyString(), any(), any(), any()))
+    void buildRisksIsolatesAcrossManagers() {
+        // ---- Data setup: two managers, each with one blocked KR on their team ----
+        Map<String, Object> krA = new HashMap<>();
+        krA.put("title", "子系统A交付受阻");
+        krA.put("real_name", "员工A");
+
+        Map<String, Object> krB = new HashMap<>();
+        krB.put("title", "子系统B接口延迟");
+        krB.put("real_name", "员工B");
+
+        // Default: blocked-KR query returns empty for any unmatched userId
+        lenient().when(jdbcTemplate.queryForList(contains("SELECT k.title"), any(), any(), any()))
                 .thenReturn((List) List.of());
-        lenient().when(jdbcTemplate.queryForObject(anyString(), eq(Integer.class), any()))
-                .thenReturn(0);
 
-        WorkspaceOverviewDto dto = workspaceService.getOverview(2L, 1L);
-        assertNotNull(dto.getRisks());
+        // Manager A (userId=2) query returns krA
+        lenient().when(jdbcTemplate.queryForList(
+                contains("SELECT k.title"), eq(1L), eq(2L), eq(2L)))
+                .thenReturn((List) List.of(krA));
+
+        // Manager B (userId=3) query returns krB
+        lenient().when(jdbcTemplate.queryForList(
+                contains("SELECT k.title"), eq(1L), eq(3L), eq(3L)))
+                .thenReturn((List) List.of(krB));
+
+        // ---- Act: each manager fetches overview ----
+        WorkspaceOverviewDto dtoA = workspaceService.getOverview(2L, 1L);
+        WorkspaceOverviewDto dtoB = workspaceService.getOverview(3L, 1L);
+
+        // ---- Assert: Manager A sees only A's risk ----
+        List<WorkspaceOverviewDto.RiskItem> risksA = dtoA.getRisks();
+        assertEquals(1, risksA.size(), "Manager A should see exactly 1 blocked KR");
+        assertEquals("BLOCKED_KR", risksA.get(0).getType());
+        assertEquals("子系统A交付受阻", risksA.get(0).getLabel());
+        assertEquals("员工A", risksA.get(0).getUserName());
+
+        // ---- Assert: Manager B sees only B's risk ----
+        List<WorkspaceOverviewDto.RiskItem> risksB = dtoB.getRisks();
+        assertEquals(1, risksB.size(), "Manager B should see exactly 1 blocked KR");
+        assertEquals("BLOCKED_KR", risksB.get(0).getType());
+        assertEquals("子系统B接口延迟", risksB.get(0).getLabel());
+        assertEquals("员工B", risksB.get(0).getUserName());
+
+        // ---- Assert: Cross-isolation — A's data differs from B's ----
+        assertNotEquals(risksA.get(0).getLabel(), risksB.get(0).getLabel(),
+                "Manager A must not see Manager B's blocked KR title");
+        assertNotEquals(risksA.get(0).getUserName(), risksB.get(0).getUserName(),
+                "Manager A must not see Manager B's subordinate name");
+
+        // ---- Verify: queryForList called with correct per-user parameters ----
+        verify(jdbcTemplate, atLeastOnce()).queryForList(
+                contains("SELECT k.title"), eq(1L), eq(2L), eq(2L));
+        verify(jdbcTemplate, atLeastOnce()).queryForList(
+                contains("SELECT k.title"), eq(1L), eq(3L), eq(3L));
     }
 
     @Test
     void getOverviewReturnsActions() {
-        lenient().when(jdbcTemplate.queryForList(anyString(), any(), any(), any()))
+        lenient().when(jdbcTemplate.queryForList(contains("SELECT k.title"), any(), any(), any()))
                 .thenReturn((List) List.of());
-        lenient().when(jdbcTemplate.queryForObject(anyString(), eq(Integer.class), any()))
-                .thenReturn(0);
 
         WorkspaceOverviewDto dto = workspaceService.getOverview(2L, 1L);
         assertNotNull(dto.getAllowedActions());