package com.battery.business.web;
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import org.junit.jupiter.api.Test;
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
import com.battery.business.service.ITestLiveService;
|
import com.ruoyi.common.exception.ServiceException;
|
|
/**
|
* SSE 推送的失败收尾:**只结束连接,不交给 MVC 的异常分发**。
|
*
|
* <p>背景(线上实测):测试被删除后,订阅它的实时页还在推,`current` 抛「测试不存在」;
|
* 原实现走 `completeWithError`,Spring 于是把异常送去全局异常处理器,而响应头已经是
|
* `text/event-stream`,写 `AjaxResult` JSON 必然失败——连锁抛出 HttpMessageNotWritableException
|
* 与安全链拒绝,每 3 秒刷一屏 ERROR。
|
*/
|
class TestLiveStreamTest
|
{
|
/** 只记录被怎么结束,不真的写出:SseEmitter 未 initialize 时 complete 是安全空操作。 */
|
private static final class RecordingEmitter extends SseEmitter
|
{
|
private boolean completed;
|
private boolean failedWithError;
|
|
private RecordingEmitter() { super(0L); }
|
|
@Override public synchronized void complete() { completed = true; super.complete(); }
|
|
@Override public synchronized void completeWithError(Throwable failure)
|
{
|
failedWithError = true;
|
super.completeWithError(failure);
|
}
|
}
|
|
@Test
|
void endsTheSubscriptionInsteadOfHandingTheFailureToMvcWhenTheTestIsGone()
|
{
|
RecordingEmitter emitter = new RecordingEmitter();
|
TestLiveStream stream = stream(emitter, testId -> { throw new ServiceException("测试不存在"); });
|
|
SseEmitter returned = stream.stream(4242L);
|
|
assertSame(emitter, returned);
|
assertTrue(emitter.completed);
|
// 关键:不走 completeWithError —— 那会把异常送进 MVC 的异常分发。
|
assertFalse(emitter.failedWithError);
|
}
|
|
@Test
|
void keepsPushingWhileTheTestIsThere()
|
{
|
RecordingEmitter emitter = new RecordingEmitter();
|
TestLiveStream stream = stream(emitter, testId -> liveState(testId));
|
|
stream.stream(7L);
|
|
assertFalse(emitter.completed);
|
assertFalse(emitter.failedWithError);
|
}
|
|
private static TestLiveStream stream(SseEmitter emitter, ITestLiveService live)
|
{
|
return new TestLiveStream(live)
|
{
|
@Override protected SseEmitter createEmitter() { return emitter; }
|
};
|
}
|
|
private static ITestLiveService.LiveState liveState(Long testId)
|
{
|
return new ITestLiveService.LiveState(testId, "RUNNING", "RECEIVING", 1L,
|
java.util.List.of(), java.util.List.of(), null);
|
}
|
}
|