| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter_tools/src/base/io.dart'; |
| import 'package:flutter_tools/src/base/logger.dart'; |
| import 'package:flutter_tools/src/build_info.dart'; |
| import 'package:flutter_tools/src/device_port_forwarder.dart'; |
| import 'package:flutter_tools/src/ios/devices.dart'; |
| import 'package:flutter_tools/src/mdns_discovery.dart'; |
| import 'package:flutter_tools/src/project.dart'; |
| import 'package:flutter_tools/src/reporting/reporting.dart'; |
| import 'package:multicast_dns/multicast_dns.dart'; |
| import 'package:test/fake.dart'; |
| |
| import '../src/common.dart'; |
| |
| void main() { |
| group('mDNS Discovery', () { |
| final int future = DateTime.now().add(const Duration(days: 1)).millisecondsSinceEpoch; |
| |
| setUp(() { |
| setNetworkInterfaceLister( |
| ({ |
| bool? includeLoopback, |
| bool? includeLinkLocal, |
| InternetAddressType? type, |
| }) async => <NetworkInterface>[], |
| ); |
| }); |
| |
| tearDown(() { |
| resetNetworkInterfaceLister(); |
| }); |
| |
| group('for attach', () { |
| late MDnsClient emptyClient; |
| |
| setUp(() { |
| emptyClient = FakeMDnsClient(<PtrResourceRecord>[], <String, List<SrvResourceRecord>>{}); |
| }); |
| |
| testWithoutContext('Find result in preliminary client', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 123, weight: 1, priority: 1, target: 'appId'), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: emptyClient, |
| preliminaryMDnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| |
| final MDnsVmServiceDiscoveryResult? result = await portDiscovery.queryForAttach(); |
| expect(result, isNotNull); |
| }); |
| |
| testWithoutContext('Do not find result in preliminary client, but find in main client', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 123, weight: 1, priority: 1, target: 'appId'), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| preliminaryMDnsClient: emptyClient, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| |
| final MDnsVmServiceDiscoveryResult? result = await portDiscovery.queryForAttach(); |
| expect(result, isNotNull); |
| }); |
| |
| testWithoutContext('Find multiple in preliminary client', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| PtrResourceRecord('baz', future, domainName: 'fiz'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 123, weight: 1, priority: 1, target: 'appId'), |
| ], |
| 'fiz': <SrvResourceRecord>[ |
| SrvResourceRecord('fiz', future, port: 321, weight: 1, priority: 1, target: 'local'), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: emptyClient, |
| preliminaryMDnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| |
| expect(portDiscovery.queryForAttach, throwsToolExit()); |
| }); |
| |
| testWithoutContext('Find duplicates in preliminary client', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 123, weight: 1, priority: 1, target: 'appId'), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: emptyClient, |
| preliminaryMDnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| |
| final MDnsVmServiceDiscoveryResult? result = await portDiscovery.queryForAttach(); |
| expect(result, isNotNull); |
| }); |
| |
| testWithoutContext('Find similar named in preliminary client', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| PtrResourceRecord('foo', future, domainName: 'bar (2)'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 123, weight: 1, priority: 1, target: 'appId'), |
| ], |
| 'bar (2)': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 123, weight: 1, priority: 1, target: 'appId'), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: emptyClient, |
| preliminaryMDnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| |
| expect(portDiscovery.queryForAttach, throwsToolExit()); |
| }); |
| |
| testWithoutContext('No ports available', () async { |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: emptyClient, |
| preliminaryMDnsClient: emptyClient, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| |
| final int? port = (await portDiscovery.queryForAttach())?.port; |
| expect(port, isNull); |
| }); |
| |
| testWithoutContext('Prints helpful message when there is no ipv4 link local address.', () async { |
| final BufferLogger logger = BufferLogger.test(); |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: emptyClient, |
| preliminaryMDnsClient: emptyClient, |
| logger: logger, |
| flutterUsage: TestUsage(), |
| ); |
| final Uri? uri = await portDiscovery.getVMServiceUriForAttach( |
| '', |
| FakeIOSDevice(), |
| ); |
| expect(uri, isNull); |
| expect(logger.errorText, contains('Personal Hotspot')); |
| }); |
| |
| testWithoutContext('One port available, no appId', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 123, weight: 1, priority: 1, target: 'appId'), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| preliminaryMDnsClient: emptyClient, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final int? port = (await portDiscovery.queryForAttach())?.port; |
| expect(port, 123); |
| }); |
| |
| testWithoutContext('One port available, no appId, with authCode', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 123, weight: 1, priority: 1, target: 'appId'), |
| ], |
| }, |
| txtResponse: <String, List<TxtResourceRecord>>{ |
| 'bar': <TxtResourceRecord>[ |
| TxtResourceRecord('bar', future, text: 'authCode=xyz\n'), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| preliminaryMDnsClient: emptyClient, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final MDnsVmServiceDiscoveryResult? result = await portDiscovery.queryForAttach(); |
| expect(result?.port, 123); |
| expect(result?.authCode, 'xyz/'); |
| }); |
| |
| testWithoutContext('Multiple ports available, with appId', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| PtrResourceRecord('baz', future, domainName: 'fiz'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 123, weight: 1, priority: 1, target: 'appId'), |
| ], |
| 'fiz': <SrvResourceRecord>[ |
| SrvResourceRecord('fiz', future, port: 321, weight: 1, priority: 1, target: 'local'), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| preliminaryMDnsClient: emptyClient, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final int? port = (await portDiscovery.queryForAttach(applicationId: 'fiz'))?.port; |
| expect(port, 321); |
| }); |
| |
| testWithoutContext('Multiple ports available per process, with appId', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| PtrResourceRecord('baz', future, domainName: 'fiz'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 1234, weight: 1, priority: 1, target: 'appId'), |
| SrvResourceRecord('bar', future, port: 123, weight: 1, priority: 1, target: 'appId'), |
| ], |
| 'fiz': <SrvResourceRecord>[ |
| SrvResourceRecord('fiz', future, port: 4321, weight: 1, priority: 1, target: 'local'), |
| SrvResourceRecord('fiz', future, port: 321, weight: 1, priority: 1, target: 'local'), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| preliminaryMDnsClient: emptyClient, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final int? port = (await portDiscovery.queryForAttach(applicationId: 'bar'))?.port; |
| expect(port, 1234); |
| }); |
| |
| testWithoutContext('Throws Exception when client throws OSError on start', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[], <String, List<SrvResourceRecord>>{}, |
| osErrorOnStart: true, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| preliminaryMDnsClient: emptyClient, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| expect( |
| () async => portDiscovery.queryForAttach(), |
| throwsException, |
| ); |
| }); |
| |
| testWithoutContext('Correctly builds VM Service URI with hostVmservicePort == 0', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 123, weight: 1, priority: 1, target: 'appId'), |
| ], |
| }, |
| ); |
| |
| final FakeIOSDevice device = FakeIOSDevice(); |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| preliminaryMDnsClient: emptyClient, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final Uri? uri = await portDiscovery.getVMServiceUriForAttach('bar', device, hostVmservicePort: 0); |
| expect(uri.toString(), 'http://127.0.0.1:123/'); |
| }); |
| |
| testWithoutContext('Get wireless device IP (iPv4)', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 1234, weight: 1, priority: 1, target: 'appId'), |
| ], |
| }, |
| ipResponse: <String, List<IPAddressResourceRecord>>{ |
| 'appId': <IPAddressResourceRecord>[ |
| IPAddressResourceRecord('Device IP', 0, address: InternetAddress.tryParse('111.111.111.111')!), |
| ], |
| }, |
| txtResponse: <String, List<TxtResourceRecord>>{ |
| 'bar': <TxtResourceRecord>[ |
| TxtResourceRecord('bar', future, text: 'authCode=xyz\n'), |
| ], |
| }, |
| ); |
| |
| final FakeIOSDevice device = FakeIOSDevice(); |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| preliminaryMDnsClient: emptyClient, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final Uri? uri = await portDiscovery.getVMServiceUriForAttach( |
| 'bar', |
| device, |
| useDeviceIPAsHost: true, |
| ); |
| expect(uri.toString(), 'http://111.111.111.111:1234/xyz/'); |
| }); |
| |
| testWithoutContext('Get wireless device IP (iPv6)', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 1234, weight: 1, priority: 1, target: 'appId'), |
| ], |
| }, |
| ipResponse: <String, List<IPAddressResourceRecord>>{ |
| 'appId': <IPAddressResourceRecord>[ |
| IPAddressResourceRecord('Device IP', 0, address: InternetAddress.tryParse('1111:1111:1111:1111:1111:1111:1111:1111')!), |
| ], |
| }, |
| txtResponse: <String, List<TxtResourceRecord>>{ |
| 'bar': <TxtResourceRecord>[ |
| TxtResourceRecord('bar', future, text: 'authCode=xyz\n'), |
| ], |
| }, |
| ); |
| |
| final FakeIOSDevice device = FakeIOSDevice(); |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| preliminaryMDnsClient: emptyClient, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final Uri? uri = await portDiscovery.getVMServiceUriForAttach( |
| 'bar', |
| device, |
| useDeviceIPAsHost: true, |
| ); |
| expect(uri.toString(), 'http://[1111:1111:1111:1111:1111:1111:1111:1111]:1234/xyz/'); |
| }); |
| |
| testWithoutContext('Throw error if unable to find VM service with app id and device port', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'srv-foo'), |
| PtrResourceRecord('bar', future, domainName: 'srv-bar'), |
| PtrResourceRecord('baz', future, domainName: 'srv-boo'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'srv-foo': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-foo', future, port: 123, weight: 1, priority: 1, target: 'target-foo'), |
| ], |
| 'srv-bar': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-bar', future, port: 123, weight: 1, priority: 1, target: 'target-bar'), |
| ], |
| 'srv-baz': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-baz', future, port: 123, weight: 1, priority: 1, target: 'target-baz'), |
| ], |
| }, |
| ); |
| final FakeIOSDevice device = FakeIOSDevice(); |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| preliminaryMDnsClient: emptyClient, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| expect( |
| portDiscovery.getVMServiceUriForAttach( |
| 'srv-bar', |
| device, |
| deviceVmservicePort: 321, |
| ), |
| throwsToolExit( |
| message: 'Did not find a Dart VM Service advertised for srv-bar on port 321.' |
| ), |
| ); |
| }); |
| |
| testWithoutContext('Throw error if unable to find VM Service with app id', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'srv-foo'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'srv-foo': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-foo', future, port: 123, weight: 1, priority: 1, target: 'target-foo'), |
| ], |
| }, |
| ); |
| final FakeIOSDevice device = FakeIOSDevice(); |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| preliminaryMDnsClient: emptyClient, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| expect( |
| portDiscovery.getVMServiceUriForAttach( |
| 'srv-asdf', |
| device, |
| ), |
| throwsToolExit( |
| message: 'Did not find a Dart VM Service advertised for srv-asdf.' |
| ), |
| ); |
| }); |
| }); |
| |
| group('for launch', () { |
| testWithoutContext('Ensure either port or device name are provided', () async { |
| final MDnsClient client = FakeMDnsClient(<PtrResourceRecord>[], <String, List<SrvResourceRecord>>{}); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| |
| expect(() async => portDiscovery.queryForLaunch(applicationId: 'app-id'), throwsAssertionError); |
| }); |
| |
| testWithoutContext('No ports available', () async { |
| final MDnsClient client = FakeMDnsClient(<PtrResourceRecord>[], <String, List<SrvResourceRecord>>{}); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| |
| final MDnsVmServiceDiscoveryResult? result = await portDiscovery.queryForLaunch( |
| applicationId: 'app-id', |
| deviceVmservicePort: 123, |
| ); |
| |
| expect(result, null); |
| }); |
| |
| testWithoutContext('Prints helpful message when there is no ipv4 link local address.', () async { |
| final MDnsClient client = FakeMDnsClient(<PtrResourceRecord>[], <String, List<SrvResourceRecord>>{}); |
| final BufferLogger logger = BufferLogger.test(); |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: logger, |
| flutterUsage: TestUsage(), |
| ); |
| |
| final Uri? uri = await portDiscovery.getVMServiceUriForLaunch( |
| '', |
| FakeIOSDevice(), |
| deviceVmservicePort: 0, |
| ); |
| expect(uri, isNull); |
| expect(logger.errorText, contains('Personal Hotspot')); |
| }); |
| |
| testWithoutContext('Throws Exception when client throws OSError on start', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[], <String, List<SrvResourceRecord>>{}, |
| osErrorOnStart: true, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| expect( |
| () async => portDiscovery.queryForLaunch(applicationId: 'app-id', deviceVmservicePort: 123), |
| throwsException, |
| ); |
| }); |
| |
| testWithoutContext('Correctly builds VM Service URI with hostVmservicePort == 0', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 123, weight: 1, priority: 1, target: 'appId'), |
| ], |
| }, |
| ); |
| |
| final FakeIOSDevice device = FakeIOSDevice(); |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final Uri? uri = await portDiscovery.getVMServiceUriForLaunch( |
| 'bar', |
| device, |
| hostVmservicePort: 0, |
| deviceVmservicePort: 123, |
| ); |
| expect(uri.toString(), 'http://127.0.0.1:123/'); |
| }); |
| |
| testWithoutContext('Get wireless device IP (iPv4)', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 1234, weight: 1, priority: 1, target: 'appId'), |
| ], |
| }, |
| ipResponse: <String, List<IPAddressResourceRecord>>{ |
| 'appId': <IPAddressResourceRecord>[ |
| IPAddressResourceRecord('Device IP', 0, address: InternetAddress.tryParse('111.111.111.111')!), |
| ], |
| }, |
| txtResponse: <String, List<TxtResourceRecord>>{ |
| 'bar': <TxtResourceRecord>[ |
| TxtResourceRecord('bar', future, text: 'authCode=xyz\n'), |
| ], |
| }, |
| ); |
| |
| final FakeIOSDevice device = FakeIOSDevice(); |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final Uri? uri = await portDiscovery.getVMServiceUriForLaunch( |
| 'bar', |
| device, |
| useDeviceIPAsHost: true, |
| deviceVmservicePort: 1234, |
| ); |
| expect(uri.toString(), 'http://111.111.111.111:1234/xyz/'); |
| }); |
| |
| testWithoutContext('Get wireless device IP (iPv6)', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'bar'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'bar': <SrvResourceRecord>[ |
| SrvResourceRecord('bar', future, port: 1234, weight: 1, priority: 1, target: 'appId'), |
| ], |
| }, |
| ipResponse: <String, List<IPAddressResourceRecord>>{ |
| 'appId': <IPAddressResourceRecord>[ |
| IPAddressResourceRecord('Device IP', 0, address: InternetAddress.tryParse('1111:1111:1111:1111:1111:1111:1111:1111')!), |
| ], |
| }, |
| txtResponse: <String, List<TxtResourceRecord>>{ |
| 'bar': <TxtResourceRecord>[ |
| TxtResourceRecord('bar', future, text: 'authCode=xyz\n'), |
| ], |
| }, |
| ); |
| |
| final FakeIOSDevice device = FakeIOSDevice(); |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final Uri? uri = await portDiscovery.getVMServiceUriForLaunch( |
| 'bar', |
| device, |
| useDeviceIPAsHost: true, |
| deviceVmservicePort: 1234, |
| ); |
| expect(uri.toString(), 'http://[1111:1111:1111:1111:1111:1111:1111:1111]:1234/xyz/'); |
| }); |
| |
| testWithoutContext('Throw error if unable to find VM Service with app id and device port', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'srv-foo'), |
| PtrResourceRecord('bar', future, domainName: 'srv-bar'), |
| PtrResourceRecord('baz', future, domainName: 'srv-boo'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'srv-foo': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-foo', future, port: 123, weight: 1, priority: 1, target: 'target-foo'), |
| ], |
| 'srv-bar': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-bar', future, port: 123, weight: 1, priority: 1, target: 'target-bar'), |
| ], |
| 'srv-baz': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-baz', future, port: 123, weight: 1, priority: 1, target: 'target-baz'), |
| ], |
| }, |
| ); |
| final FakeIOSDevice device = FakeIOSDevice(); |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| expect( |
| portDiscovery.getVMServiceUriForLaunch( |
| 'srv-bar', |
| device, |
| deviceVmservicePort: 321, |
| ), |
| throwsToolExit( |
| message:'Did not find a Dart VM Service advertised for srv-bar on port 321.'), |
| ); |
| }); |
| |
| testWithoutContext('Matches on application id and device name', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'srv-foo'), |
| PtrResourceRecord('bar', future, domainName: 'srv-bar'), |
| PtrResourceRecord('baz', future, domainName: 'srv-boo'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'srv-bar': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-foo', future, port: 123, weight: 1, priority: 1, target: 'My-Phone.local'), |
| ], |
| }, |
| ); |
| final FakeIOSDevice device = FakeIOSDevice( |
| name: 'My Phone', |
| ); |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| |
| final Uri? uri = await portDiscovery.getVMServiceUriForLaunch( |
| 'srv-bar', |
| device, |
| ); |
| expect(uri.toString(), 'http://127.0.0.1:123/'); |
| }); |
| |
| testWithoutContext('Throw error if unable to find VM Service with app id and device name', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'srv-foo'), |
| PtrResourceRecord('bar', future, domainName: 'srv-bar'), |
| PtrResourceRecord('baz', future, domainName: 'srv-boo'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'srv-foo': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-foo', future, port: 123, weight: 1, priority: 1, target: 'target-foo'), |
| ], |
| }, |
| ); |
| final FakeIOSDevice device = FakeIOSDevice( |
| name: 'My Phone', |
| ); |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| expect( |
| portDiscovery.getVMServiceUriForLaunch( |
| 'srv-bar', |
| device, |
| ), |
| throwsToolExit( |
| message:'Did not find a Dart VM Service advertised for srv-bar'), |
| ); |
| }); |
| }); |
| |
| group('deviceNameMatchesTargetName', () { |
| testWithoutContext('compares case insensitive and without spaces, hypthens, .local', () { |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: FakeMDnsClient( |
| <PtrResourceRecord>[], |
| <String, List<SrvResourceRecord>>{}, |
| ), |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| |
| expect(portDiscovery.deviceNameMatchesTargetName('My phone', 'My-Phone.local'), isTrue); |
| }); |
| |
| testWithoutContext('includes numbers in comparison', () { |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: FakeMDnsClient( |
| <PtrResourceRecord>[], |
| <String, List<SrvResourceRecord>>{}, |
| ), |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| expect(portDiscovery.deviceNameMatchesTargetName('My phone', 'My-Phone-2.local'), isFalse); |
| }); |
| }); |
| |
| testWithoutContext('Find firstMatchingVmService with many available and no application id', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'srv-foo'), |
| PtrResourceRecord('bar', future, domainName: 'srv-bar'), |
| PtrResourceRecord('baz', future, domainName: 'srv-boo'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'srv-foo': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-foo', future, port: 123, weight: 1, priority: 1, target: 'target-foo'), |
| ], |
| 'srv-bar': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-bar', future, port: 123, weight: 1, priority: 1, target: 'target-bar'), |
| ], |
| 'srv-baz': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-baz', future, port: 123, weight: 1, priority: 1, target: 'target-baz'), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final MDnsVmServiceDiscoveryResult? result = await portDiscovery.firstMatchingVmService(client); |
| expect(result?.domainName, 'srv-foo'); |
| }); |
| |
| testWithoutContext('Find firstMatchingVmService app id', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'srv-foo'), |
| PtrResourceRecord('bar', future, domainName: 'srv-bar'), |
| PtrResourceRecord('baz', future, domainName: 'srv-boo'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'srv-foo': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-foo', future, port: 111, weight: 1, priority: 1, target: 'target-foo'), |
| ], |
| 'srv-bar': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-bar', future, port: 222, weight: 1, priority: 1, target: 'target-bar'), |
| SrvResourceRecord('srv-bar', future, port: 333, weight: 1, priority: 1, target: 'target-bar-2'), |
| ], |
| 'srv-baz': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-baz', future, port: 444, weight: 1, priority: 1, target: 'target-baz'), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final MDnsVmServiceDiscoveryResult? result = await portDiscovery.firstMatchingVmService( |
| client, |
| applicationId: 'srv-bar' |
| ); |
| expect(result?.domainName, 'srv-bar'); |
| expect(result?.port, 222); |
| }); |
| testWithoutContext('find with no txt record', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'srv-foo'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'srv-foo': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-foo', future, port: 111, weight: 1, priority: 1, target: 'target-foo'), |
| ], |
| }, |
| ipResponse: <String, List<IPAddressResourceRecord>>{ |
| 'target-foo': <IPAddressResourceRecord>[ |
| IPAddressResourceRecord('target-foo', 0, address: InternetAddress.tryParse('111.111.111.111')!), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final MDnsVmServiceDiscoveryResult? result = await portDiscovery.firstMatchingVmService( |
| client, |
| applicationId: 'srv-foo', |
| useDeviceIPAsHost: true, |
| ); |
| expect(result?.domainName, 'srv-foo'); |
| expect(result?.port, 111); |
| expect(result?.authCode, ''); |
| expect(result?.ipAddress?.address, '111.111.111.111'); |
| }); |
| testWithoutContext('find with empty txt record', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'srv-foo'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'srv-foo': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-foo', future, port: 111, weight: 1, priority: 1, target: 'target-foo'), |
| ], |
| }, |
| txtResponse: <String, List<TxtResourceRecord>>{ |
| 'srv-foo': <TxtResourceRecord>[ |
| TxtResourceRecord('srv-foo', future, text: ''), |
| ], |
| }, |
| ipResponse: <String, List<IPAddressResourceRecord>>{ |
| 'target-foo': <IPAddressResourceRecord>[ |
| IPAddressResourceRecord('target-foo', 0, address: InternetAddress.tryParse('111.111.111.111')!), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final MDnsVmServiceDiscoveryResult? result = await portDiscovery.firstMatchingVmService( |
| client, |
| applicationId: 'srv-foo', |
| useDeviceIPAsHost: true, |
| ); |
| expect(result?.domainName, 'srv-foo'); |
| expect(result?.port, 111); |
| expect(result?.authCode, ''); |
| expect(result?.ipAddress?.address, '111.111.111.111'); |
| }); |
| testWithoutContext('find with valid txt record', () async { |
| final MDnsClient client = FakeMDnsClient( |
| <PtrResourceRecord>[ |
| PtrResourceRecord('foo', future, domainName: 'srv-foo'), |
| ], |
| <String, List<SrvResourceRecord>>{ |
| 'srv-foo': <SrvResourceRecord>[ |
| SrvResourceRecord('srv-foo', future, port: 111, weight: 1, priority: 1, target: 'target-foo'), |
| ], |
| }, |
| txtResponse: <String, List<TxtResourceRecord>>{ |
| 'srv-foo': <TxtResourceRecord>[ |
| TxtResourceRecord('srv-foo', future, text: 'authCode=xyz\n'), |
| ], |
| }, |
| ipResponse: <String, List<IPAddressResourceRecord>>{ |
| 'target-foo': <IPAddressResourceRecord>[ |
| IPAddressResourceRecord('target-foo', 0, address: InternetAddress.tryParse('111.111.111.111')!), |
| ], |
| }, |
| ); |
| |
| final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( |
| mdnsClient: client, |
| logger: BufferLogger.test(), |
| flutterUsage: TestUsage(), |
| ); |
| final MDnsVmServiceDiscoveryResult? result = await portDiscovery.firstMatchingVmService( |
| client, |
| applicationId: 'srv-foo', |
| useDeviceIPAsHost: true, |
| ); |
| expect(result?.domainName, 'srv-foo'); |
| expect(result?.port, 111); |
| expect(result?.authCode, 'xyz/'); |
| expect(result?.ipAddress?.address, '111.111.111.111'); |
| }); |
| }); |
| } |
| |
| class FakeMDnsClient extends Fake implements MDnsClient { |
| FakeMDnsClient(this.ptrRecords, this.srvResponse, { |
| this.txtResponse = const <String, List<TxtResourceRecord>>{}, |
| this.ipResponse = const <String, List<IPAddressResourceRecord>>{}, |
| this.osErrorOnStart = false, |
| }); |
| |
| final List<PtrResourceRecord> ptrRecords; |
| final Map<String, List<SrvResourceRecord>> srvResponse; |
| final Map<String, List<TxtResourceRecord>> txtResponse; |
| final Map<String, List<IPAddressResourceRecord>> ipResponse; |
| final bool osErrorOnStart; |
| |
| @override |
| Future<void> start({ |
| InternetAddress? listenAddress, |
| NetworkInterfacesFactory? interfacesFactory, |
| int mDnsPort = 5353, |
| InternetAddress? mDnsAddress, |
| }) async { |
| if (osErrorOnStart) { |
| throw const OSError('Operation not supported on socket', 102); |
| } |
| } |
| |
| @override |
| Stream<T> lookup<T extends ResourceRecord>( |
| ResourceRecordQuery query, { |
| Duration timeout = const Duration(seconds: 5), |
| }) { |
| if (T == PtrResourceRecord && query.fullyQualifiedName == MDnsVmServiceDiscovery.dartVmServiceName) { |
| return Stream<PtrResourceRecord>.fromIterable(ptrRecords) as Stream<T>; |
| } |
| if (T == SrvResourceRecord) { |
| final String key = query.fullyQualifiedName; |
| return Stream<SrvResourceRecord>.fromIterable(srvResponse[key] ?? <SrvResourceRecord>[]) as Stream<T>; |
| } |
| if (T == TxtResourceRecord) { |
| final String key = query.fullyQualifiedName; |
| return Stream<TxtResourceRecord>.fromIterable(txtResponse[key] ?? <TxtResourceRecord>[]) as Stream<T>; |
| } |
| if (T == IPAddressResourceRecord) { |
| final String key = query.fullyQualifiedName; |
| return Stream<IPAddressResourceRecord>.fromIterable(ipResponse[key] ?? <IPAddressResourceRecord>[]) as Stream<T>; |
| } |
| throw UnsupportedError('Unsupported query type $T'); |
| } |
| |
| @override |
| void stop() {} |
| } |
| |
| // Unfortunately Device, despite not being immutable, has an `operator ==`. |
| // Until we fix that, we have to also ignore related lints here. |
| // ignore: avoid_implementing_value_types |
| class FakeIOSDevice extends Fake implements IOSDevice { |
| FakeIOSDevice({this.name = 'iPhone'}); |
| |
| @override |
| final String name; |
| |
| @override |
| Future<TargetPlatform> get targetPlatform async => TargetPlatform.ios; |
| |
| @override |
| bool isSupported() => true; |
| |
| @override |
| bool isSupportedForProject(FlutterProject flutterProject) => true; |
| |
| @override |
| DevicePortForwarder get portForwarder => const NoOpDevicePortForwarder(); |
| } |