|
|
@@ -84,9 +84,10 @@ class ChatAttachmentServiceTest {
|
|
|
@DisplayName("草稿期附件(sessionId=0)发送时绑定到当前会话")
|
|
|
void bindsDraftAttachmentToSession() {
|
|
|
when(mapper.selectById(10L)).thenReturn(att(10L, 1L, 1L, 0L, "TABLE"));
|
|
|
+ when(mapper.update(any(), any())).thenReturn(1); // CAS 绑定成功
|
|
|
List<String> blocks = service.buildBlocks(List.of(10L), 1L, 1L, 55L, "问题");
|
|
|
assertEquals(1, blocks.size());
|
|
|
- // 绑定动作发生在加载阶段(update 换 sessionId)
|
|
|
+ // 绑定动作发生在加载阶段(CAS 条件更新换 sessionId)
|
|
|
verify(mapper).update(any(), any());
|
|
|
}
|
|
|
|
|
|
@@ -155,6 +156,29 @@ class ChatAttachmentServiceTest {
|
|
|
assertEquals("attachment", ChatAttachmentService.sanitizeFileName(""));
|
|
|
}
|
|
|
|
|
|
+ @Test
|
|
|
+ @DisplayName("并发抢绑同一草稿附件:CAS 失败方重读后必须拒绝(多用户多端互斥)")
|
|
|
+ void concurrentBindOnlyOneWins() {
|
|
|
+ ChatAttachment draft = att(11L, 1L, 1L, 0L, "TABLE");
|
|
|
+ when(mapper.selectById(11L)).thenReturn(draft);
|
|
|
+ // 模拟对方抢先绑定:本次 CAS 更新影响 0 行,重读后归属已是对方的会话
|
|
|
+ when(mapper.update(any(), any())).thenReturn(0);
|
|
|
+ ChatAttachment stolen = att(11L, 1L, 1L, 777L, "TABLE");
|
|
|
+ when(mapper.selectById(11L)).thenReturn(draft, stolen);
|
|
|
+ ServerException e = assertThrows(ServerException.class,
|
|
|
+ () -> service.buildBlocks(List.of(11L), 1L, 1L, 55L, "问题"));
|
|
|
+ assertTrue(e.getMessage().contains("已被其他消息使用"), e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ @DisplayName("CAS 成功(影响 1 行)则正常绑定放行")
|
|
|
+ void concurrentBindWinnerProceeds() {
|
|
|
+ when(mapper.selectById(12L)).thenReturn(att(12L, 1L, 1L, 0L, "TABLE"));
|
|
|
+ when(mapper.update(any(), any())).thenReturn(1);
|
|
|
+ List<String> blocks = service.buildBlocks(List.of(12L), 1L, 1L, 55L, "问题");
|
|
|
+ assertEquals(1, blocks.size());
|
|
|
+ }
|
|
|
+
|
|
|
@Test
|
|
|
@DisplayName("无附件时空列表,不动库")
|
|
|
void emptyIdsNoop() {
|