| | |
| | | |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.net.InetAddress; |
| | | import java.net.InetSocketAddress; |
| | | import java.net.ServerSocket; |
| | | import java.net.Socket; |
| | | import java.net.SocketException; |
| | |
| | | import java.util.concurrent.Executors; |
| | | import java.util.concurrent.LinkedBlockingQueue; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.function.Function; |
| | | |
| | | /** |
| | | * 提供可复用的 BTS TCP 脚本设备边界,用于闭环与恢复测试。 |
| | |
| | | private final ExecutorService executor = Executors.newSingleThreadExecutor(); |
| | | private final BlockingQueue<ScriptedAction> actions = new LinkedBlockingQueue<>(); |
| | | private final List<String> requests = new CopyOnWriteArrayList<>(); |
| | | private final Function<String, String> responseProvider; |
| | | |
| | | public ScriptedBtsTcpSimulator() throws IOException |
| | | { |
| | | this(true); |
| | | this(0, true, null); |
| | | } |
| | | |
| | | private ScriptedBtsTcpSimulator(boolean acceptConnections) throws IOException |
| | | private ScriptedBtsTcpSimulator(int port, boolean acceptConnections, |
| | | Function<String, String> responseProvider) throws IOException |
| | | { |
| | | serverSocket = new ServerSocket(0); |
| | | port = serverSocket.getLocalPort(); |
| | | if (port < 0 || port > 65535) throw new IllegalArgumentException("port must be between 0 and 65535"); |
| | | this.responseProvider = responseProvider; |
| | | serverSocket = new ServerSocket(); |
| | | serverSocket.bind(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), port)); |
| | | this.port = serverSocket.getLocalPort(); |
| | | if (acceptConnections) |
| | | executor.submit(this::serve); |
| | | else |
| | |
| | | |
| | | public static ScriptedBtsTcpSimulator refusingConnections() throws IOException |
| | | { |
| | | return new ScriptedBtsTcpSimulator(false); |
| | | return new ScriptedBtsTcpSimulator(0, false, null); |
| | | } |
| | | |
| | | /** 创建仅监听本机、可按请求持续生成响应的模拟器。 */ |
| | | public static ScriptedBtsTcpSimulator responding(int port, Function<String, String> responseProvider) |
| | | throws IOException |
| | | { |
| | | if (responseProvider == null) throw new IllegalArgumentException("responseProvider must not be null"); |
| | | return new ScriptedBtsTcpSimulator(port, true, responseProvider); |
| | | } |
| | | |
| | | public int port() |
| | |
| | | while (!socket.isClosed()) |
| | | { |
| | | String request = readFrame(socket.getInputStream()); |
| | | requests.add(request); |
| | | ScriptedAction action = actions.poll(5, TimeUnit.SECONDS); |
| | | if (responseProvider == null) requests.add(request); |
| | | ScriptedAction action = responseProvider == null |
| | | ? actions.poll(5, TimeUnit.SECONDS) |
| | | : new ScriptedAction(Duration.ZERO, |
| | | responseProvider.apply(request).getBytes(StandardCharsets.UTF_8), false); |
| | | if (action == null) throw new IOException("No scripted BTS action available"); |
| | | TimeUnit.MILLISECONDS.sleep(action.delay().toMillis()); |
| | | if (action.disconnect()) return; |