- 服务端: RTTY_TOKEN 最小鉴权; Ready.resumed 会话恢复语义; 会话按 ID 原子创建 - 服务端: 桌面端连接/重连时全屏 ANSI 重绘; 惰性语义快照(仅移动端订阅时生成); Ping/Pong 心跳 - 桌面端: 输入改二进制帧无损透传; 指数退避自动重连; token 输入框; resumed 状态展示 - 移动端: 修复 client=mobile 参数(此前永远收不到快照); 新增最小验证 App(连接/快照显示/输入/Keybar); 支持 token; Android 网络权限 - 测试: 修正 e2e onReady 签名; 新增移动端 widget 测试
69 lines
2.4 KiB
Dart
69 lines
2.4 KiB
Dart
// 端到端集成测试:桌面端连接层(RttyPtyBackend)↔ Rust 服务端。
|
||
//
|
||
// 运行前需先启动 Rust 服务端:cd .. && cargo run
|
||
// 运行:flutter test test/e2e_ws_test.dart
|
||
import 'dart:typed_data';
|
||
|
||
import 'package:flutter_test/flutter_test.dart';
|
||
|
||
import 'package:rtty_desktop/src/rtty_pty_backend.dart';
|
||
|
||
import 'support.dart';
|
||
|
||
void main() {
|
||
TestWidgetsFlutterBinding.ensureInitialized();
|
||
|
||
test('RttyPtyBackend connects to Rust server and receives raw ANSI output',
|
||
() async {
|
||
if (!await isServerUp('127.0.0.1', 8080)) {
|
||
markTestSkipped('Rtty server not running');
|
||
return;
|
||
}
|
||
final backend = RttyPtyBackend();
|
||
|
||
final states = <ConnState>[];
|
||
String? sessionId;
|
||
final raw = StringBuffer();
|
||
backend.onStateChanged = (s) => states.add(s);
|
||
backend.onReady = (id, cols, rows, resumed) =>
|
||
sessionId = '$id:$cols:$rows:$resumed';
|
||
backend.output.listen((Uint8List b) {
|
||
raw.write(String.fromCharCodes(b));
|
||
});
|
||
|
||
await backend.connect(host: '127.0.0.1', port: 8080);
|
||
|
||
// 等待连接就绪(socket 已连接 + 收到 ready 帧)。
|
||
final deadline = DateTime.now().add(const Duration(seconds: 5));
|
||
while ((backend.state != ConnState.connected || sessionId == null) &&
|
||
DateTime.now().isBefore(deadline)) {
|
||
await Future<void>.delayed(const Duration(milliseconds: 100));
|
||
}
|
||
|
||
expect(backend.state, ConnState.connected,
|
||
reason: '未能连接服务端 states=$states');
|
||
expect(sessionId, isNotNull, reason: '未收到 ready 帧 states=$states');
|
||
|
||
// 发送命令,等待回显。
|
||
backend.write(Uint8List.fromList(
|
||
'echo RTTY_E2E_${DateTime.now().millisecondsSinceEpoch}\r\n'.codeUnits));
|
||
|
||
String? matchedLine;
|
||
final outDeadline = DateTime.now().add(const Duration(seconds: 8));
|
||
while (DateTime.now().isBefore(outDeadline)) {
|
||
await Future<void>.delayed(const Duration(milliseconds: 150));
|
||
final text = raw.toString();
|
||
final lines = text.split('\n');
|
||
matchedLine = lines.where((l) => l.contains('RTTY_E2E')).lastOrNull;
|
||
if (matchedLine != null) break;
|
||
}
|
||
|
||
expect(matchedLine, isNotNull,
|
||
reason: '未捕获到命令回显。流末尾:'
|
||
'${raw.toString().length > 200 ? raw.toString().substring(raw.toString().length - 200) : raw.toString()}');
|
||
|
||
await backend.close();
|
||
expect(backend.state, ConnState.disconnected);
|
||
});
|
||
}
|