diff --git a/test/support/fake_dns.dart b/test/support/fake_dns.dart index 83ef0ee..adfc983 100644 --- a/test/support/fake_dns.dart +++ b/test/support/fake_dns.dart @@ -20,6 +20,24 @@ class FakeDns { int get port => _udp.port; + /// 그 번호로 UDP 를 연다 (못 열면 null). 전체 시험 (10/20) 에서 막힌 포트 (10013) 의 오류가 try 밖으로 (잡히지 않은 비동기 오류로) + /// 나와 시험이 실패한 적이 있어, 열기 하나를 따로 영역 (zone) 에서 돌려 어느 쪽으로 오든 "못 열었음" 으로 받는다 + Future _tryUdp(int port) { + final done = Completer(); + runZonedGuarded(() async { + final s = await RawDatagramSocket.bind(InternetAddress.loopbackIPv4, port); + if (done.isCompleted) { + s.close(); + } else { + done.complete(s); + } + }, (e, _) { + events.add('udp bind $port failed: ${e is SocketException ? '${e.osError?.errorCode} ${e.message}' : e}'); + if (!done.isCompleted) done.complete(null); + }); + return done.future; + } + Future start() async { if (!truncateUdp) { _udp = await RawDatagramSocket.bind(InternetAddress.loopbackIPv4, 0); @@ -29,16 +47,15 @@ class FakeDns { // 그 번호의 UDP 가 막혀 있거나 (10013) 쓰는 중이면 다른 번호로 다시 for (var i = 0;; i++) { final tcp = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0); - try { - _udp = await RawDatagramSocket.bind(InternetAddress.loopbackIPv4, tcp.port); + final udp = await _tryUdp(tcp.port); + if (udp != null) { + _udp = udp; _tcp = tcp; events.add('bound tcp+udp ${tcp.port} (try $i)'); break; - } on SocketException catch (e) { - events.add('udp bind ${tcp.port} failed: ${e.osError?.errorCode} ${e.message}'); - await tcp.close(); - if (i > 50) rethrow; } + await tcp.close(); + if (i > 50) throw StateError('UDP 포트를 열지 못함: $events'); } } _udp.listen((e) {