Files
JChargePointProtocol/jcpp-protocol-api/src/test/java/sanbing/jcpp/protocol/provider/ProtocolSessionCloseCallbackTest.java
2026-06-10 14:26:04 +08:00

174 lines
6.2 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程https://www.bilibili.com/cheese/play/ss942400790
*/
package sanbing.jcpp.protocol.provider;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sanbing.jcpp.proto.gen.DownlinkProto.DownlinkRequestMessage;
import sanbing.jcpp.proto.gen.UplinkProto.SessionCloseReason;
import sanbing.jcpp.protocol.domain.ProtocolSession;
import sanbing.jcpp.protocol.provider.impl.DefaultProtocolSessionRegistryProvider;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.jupiter.api.Assertions.*;
/**
* 会话关闭回调单元测试
* 测试 ProtocolSession 关闭时自动清除 Caffeine 缓存功能
*
* @author 九筒
*/
class ProtocolSessionCloseCallbackTest {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private DefaultProtocolSessionRegistryProvider sessionRegistryProvider;
@BeforeEach
void setUp() {
sessionRegistryProvider = new DefaultProtocolSessionRegistryProvider();
}
/**
* 测试:会话关闭后应自动从缓存中移除
*/
@Test
void testSessionRemovedFromCacheOnClose() {
log.info("开始测试:会话关闭后应自动从缓存中移除");
// 1. 创建并注册会话
TestProtocolSession session = new TestProtocolSession("testProtocol");
UUID sessionId = session.getId();
sessionRegistryProvider.register(session);
log.info("会话已注册: sessionId={}", sessionId);
// 2. 验证会话存在于缓存中
ProtocolSession sessionFromCache = sessionRegistryProvider.get(sessionId);
assertNotNull(sessionFromCache, "注册后会话应存在于缓存中");
assertEquals(sessionId, sessionFromCache.getId(), "会话ID应匹配");
log.info("验证会话存在于缓存中");
// 3. 关闭会话
session.close(SessionCloseReason.SESSION_CLOSE_ON_CHANNEL_INACTIVE);
log.info("会话已关闭");
// 4. 验证会话已从缓存中移除
ProtocolSession sessionAfterClose = sessionRegistryProvider.get(sessionId);
assertNull(sessionAfterClose, "关闭后会话应从缓存中移除");
log.info("验证会话已从缓存中移除");
// 5. 验证会话状态
assertTrue(session.isClosed(), "会话 closed 状态应为 true");
log.info("验证会话 closed 状态为 true");
log.info("测试通过:会话关闭后自动从缓存中移除");
}
/**
* 测试:重复关闭会话不应抛出异常,且回调只执行一次
*/
@Test
void testDuplicateCloseExecutesCallbackOnce() {
log.info("开始测试:重复关闭会话回调只执行一次");
// 使用计数器跟踪回调执行次数
AtomicInteger callbackCount = new AtomicInteger(0);
// 1. 创建会话并设置自定义回调
TestProtocolSession session = new TestProtocolSession("testProtocol");
session.setCloseCallback(id -> {
callbackCount.incrementAndGet();
log.info("回调执行,当前次数: {}", callbackCount.get());
});
// 2. 第一次关闭
session.close(SessionCloseReason.SESSION_CLOSE_ON_CHANNEL_INACTIVE);
assertEquals(1, callbackCount.get(), "第一次关闭后回调应执行1次");
assertTrue(session.isClosed(), "第一次关闭后应为 closed 状态");
// 3. 第二次关闭(应被忽略)
assertDoesNotThrow(() -> session.close(SessionCloseReason.SESSION_CLOSE_DESTRUCTION));
assertEquals(1, callbackCount.get(), "重复关闭后回调仍应只执行1次");
assertTrue(session.isClosed(), "重复关闭后仍应为 closed 状态");
// 4. 第三次关闭(应被忽略)
assertDoesNotThrow(() -> session.close());
assertEquals(1, callbackCount.get(), "再次重复关闭后回调仍应只执行1次");
log.info("测试通过:重复关闭只触发一次回调");
}
/**
* 测试register 时会自动设置 closeCallback
*/
@Test
void testRegisterSetsCloseCallback() {
log.info("开始测试register 时会自动设置 closeCallback");
// 1. 创建会话(此时 closeCallback 为 null
TestProtocolSession session = new TestProtocolSession("testProtocol");
assertNull(session.getCloseCallback(), "注册前 closeCallback 应为 null");
// 2. 注册会话
sessionRegistryProvider.register(session);
// 3. 验证 closeCallback 已设置
assertNotNull(session.getCloseCallback(), "注册后 closeCallback 应已设置");
log.info("验证 closeCallback 已设置");
// 4. 验证关闭时能正确清除缓存
UUID sessionId = session.getId();
assertNotNull(sessionRegistryProvider.get(sessionId), "关闭前会话应存在");
session.close();
assertNull(sessionRegistryProvider.get(sessionId), "关闭后会话应被移除");
log.info("验证关闭时正确清除缓存");
log.info("测试通过register 自动设置 closeCallback");
}
/**
* 测试isClosed 方法正确反映会话状态
*/
@Test
void testIsClosedReflectsSessionState() {
log.info("开始测试isClosed 方法正确反映会话状态");
TestProtocolSession session = new TestProtocolSession("testProtocol");
// 新建会话应未关闭
assertFalse(session.isClosed(), "新建会话应未关闭");
// 关闭后应为已关闭
session.close();
assertTrue(session.isClosed(), "关闭后应为已关闭");
log.info("测试通过isClosed 方法正确反映会话状态");
}
/**
* 测试用的 ProtocolSession 实现
*/
private static class TestProtocolSession extends ProtocolSession {
public TestProtocolSession(String protocolName) {
super(protocolName);
}
@Override
public void onDownlink(DownlinkRequestMessage downlinkMsg) {
// 测试用空实现
}
}
}