9dfa06ffee
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Signed-off-by: cls_宁波本机 <908705107@qq.com>
112 lines
3.0 KiB
Dart
112 lines
3.0 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:buzz/shared/relay/relay_socket.dart';
|
|
import 'package:crypto/crypto.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
/// A server that completes the WS handshake then never speaks again: no pongs,
|
|
/// no close frame. Only a client-side ping timeout can notice.
|
|
Future<ServerSocket> _silentAfterHandshakeServer() async {
|
|
final server = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0);
|
|
server.listen((client) {
|
|
client.listen(
|
|
(data) {
|
|
final match = RegExp(
|
|
r'Sec-WebSocket-Key: (.*)\r\n',
|
|
caseSensitive: false,
|
|
).firstMatch(String.fromCharCodes(data));
|
|
if (match == null) return;
|
|
final accept = base64.encode(
|
|
sha1
|
|
.convert(
|
|
utf8.encode(
|
|
'${match.group(1)!.trim()}258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
|
|
),
|
|
)
|
|
.bytes,
|
|
);
|
|
client.write(
|
|
'HTTP/1.1 101 Switching Protocols\r\n'
|
|
'Upgrade: websocket\r\nConnection: Upgrade\r\n'
|
|
'Sec-WebSocket-Accept: $accept\r\n\r\n',
|
|
);
|
|
},
|
|
onError: (_) {},
|
|
onDone: () {},
|
|
);
|
|
});
|
|
return server;
|
|
}
|
|
|
|
void main() {
|
|
const testPingInterval = Duration(milliseconds: 150);
|
|
|
|
setUp(() {
|
|
RelaySocket.debugPingInterval = testPingInterval;
|
|
});
|
|
|
|
tearDown(() {
|
|
RelaySocket.debugPingInterval = RelaySocket.pingInterval;
|
|
});
|
|
|
|
test('detects a peer that stops answering pings', () async {
|
|
final server = await _silentAfterHandshakeServer();
|
|
|
|
final disconnected = Completer<Object?>();
|
|
final socket = RelaySocket(
|
|
wsUrl: 'ws://127.0.0.1:${server.port}',
|
|
nsec: null,
|
|
onMessage: (_) {},
|
|
onConnected: () {},
|
|
onDisconnected: (error) {
|
|
if (!disconnected.isCompleted) disconnected.complete(error);
|
|
},
|
|
);
|
|
unawaited(socket.connect());
|
|
|
|
var detected = true;
|
|
try {
|
|
await disconnected.future.timeout(testPingInterval * 4);
|
|
} on TimeoutException {
|
|
detected = false;
|
|
}
|
|
|
|
expect(
|
|
detected,
|
|
isTrue,
|
|
reason:
|
|
'RelaySocket must surface an unanswered ping through onDisconnected',
|
|
);
|
|
|
|
socket.dispose();
|
|
await server.close();
|
|
});
|
|
|
|
test('keeps an idle but healthy peer connected', () async {
|
|
final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
|
|
server.transform(WebSocketTransformer()).listen((ws) {
|
|
// A healthy relay answers pings without sending application data.
|
|
ws.listen((_) {}, onError: (_) {}, onDone: () {});
|
|
});
|
|
|
|
var tornDown = false;
|
|
final socket = RelaySocket(
|
|
wsUrl: 'ws://127.0.0.1:${server.port}',
|
|
nsec: null,
|
|
onMessage: (_) {},
|
|
onConnected: () {},
|
|
onDisconnected: (_) => tornDown = true,
|
|
);
|
|
unawaited(socket.connect());
|
|
|
|
await Future<void>.delayed(testPingInterval * 4);
|
|
|
|
expect(tornDown, isFalse);
|
|
|
|
await socket.disconnect();
|
|
await server.close(force: true);
|
|
});
|
|
}
|