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"));
}
}
}