package com.ruoyi.device.bts; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.Duration; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.junit.jupiter.api.Test; class BtsTcpTransportTest { @Test void framesRequestsAndSerializesConcurrentExchanges() throws Exception { try (ScriptedBtsTcpSimulator simulator = new ScriptedBtsTcpSimulator(); BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", simulator.port(), Duration.ofSeconds(1), Duration.ofSeconds(2))) { ExecutorService callers = Executors.newFixedThreadPool(2); try { simulator.enqueue("first_resp"); simulator.enqueue("second_resp"); Callable first = () -> transport.exchange("first检测"); Callable second = () -> transport.exchange("second"); Future firstResult = callers.submit(first); Future secondResult = callers.submit(second); Set responses = Set.of(firstResult.get(), secondResult.get()); assertEquals(Set.of("first_resp", "second_resp"), responses); assertEquals(2, simulator.requests().size()); assertTrue(simulator.requests().stream().allMatch(request -> request.startsWith(""))); assertTrue(simulator.requests().stream().anyMatch(request -> request.contains("检测"))); } finally { callers.shutdownNow(); } } } @Test void reportsDelayedResponseAsTimeout() throws Exception { try (ScriptedBtsTcpSimulator simulator = new ScriptedBtsTcpSimulator(); BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", simulator.port(), Duration.ofSeconds(1), Duration.ofMillis(50))) { simulator.enqueueDelayed(Duration.ofMillis(200), "late_resp"); BtsTransportException exception = assertThrows(BtsTransportException.class, () -> transport.exchange("late")); assertEquals(BtsTransportException.Reason.TIMEOUT, exception.reason()); } } @Test void reportsActiveDisconnectAndReconnectsOnNextExchange() throws Exception { try (ScriptedBtsTcpSimulator simulator = new ScriptedBtsTcpSimulator(); BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", simulator.port(), Duration.ofSeconds(1), Duration.ofSeconds(1))) { simulator.enqueueDisconnect(); BtsTransportException exception = assertThrows(BtsTransportException.class, () -> transport.exchange("first")); assertEquals(BtsTransportException.Reason.DISCONNECTED, exception.reason()); simulator.enqueue("second_resp"); assertEquals("second_resp", transport.exchange("second")); assertEquals(2, simulator.requests().size()); } } @Test void rejectsResponseLargerThanConfiguredLimit() throws Exception { try (ScriptedBtsTcpSimulator simulator = new ScriptedBtsTcpSimulator(); BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", simulator.port(), Duration.ofSeconds(1), Duration.ofSeconds(1), 32)) { simulator.enqueue("x".repeat(33)); BtsTransportException exception = assertThrows(BtsTransportException.class, () -> transport.exchange("large")); assertEquals(BtsTransportException.Reason.RESPONSE_TOO_LARGE, exception.reason()); } } @Test void reportsRefusedConnection() throws Exception { try (ScriptedBtsTcpSimulator simulator = ScriptedBtsTcpSimulator.refusingConnections(); BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", simulator.port(), Duration.ofSeconds(1), Duration.ofSeconds(1))) { BtsTransportException exception = assertThrows(BtsTransportException.class, () -> transport.exchange("getdevinfo")); assertEquals(BtsTransportException.Reason.CONNECTION_FAILED, exception.reason()); assertTrue(simulator.requests().isEmpty()); } } @Test void rejectsResponseTimeoutAboveProtocolMaximum() { assertThrows(IllegalArgumentException.class, () -> new BtsTcpTransport("127.0.0.1", 502, Duration.ofSeconds(1), Duration.ofSeconds(31))); } @Test void rejectsResponseThatIsNotValidUtf8() throws Exception { try (ScriptedBtsTcpSimulator simulator = new ScriptedBtsTcpSimulator(); BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", simulator.port(), Duration.ofSeconds(1), Duration.ofSeconds(1))) { simulator.enqueueRaw(new byte[] {(byte) 0xC3, (byte) 0x28}); BtsTransportException exception = assertThrows(BtsTransportException.class, () -> transport.exchange("getdevinfo")); assertEquals(BtsTransportException.Reason.INVALID_UTF8, exception.reason()); } } @Test void acceptsResponseAtSizeLimitAndDelimiterPrefixInPayload() throws Exception { try (ScriptedBtsTcpSimulator simulator = new ScriptedBtsTcpSimulator(); BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", simulator.port(), Duration.ofSeconds(1), Duration.ofSeconds(1), 32)) { String atLimit = "x".repeat(32); simulator.enqueue(atLimit); simulator.enqueue("#"); assertEquals(atLimit, transport.exchange("first")); assertEquals("#", transport.exchange("second")); } } }