Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
cbf2e168
Unverified
Commit
cbf2e168
authored
Jan 19, 2023
by
Jenn Magder
Committed by
GitHub
Jan 19, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Support iOS wireless debugging (#118104)" (#118826)
This reverts commit
5cd2d4c6
.
parent
5cd2d4c6
Changes
15
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
330 additions
and
1745 deletions
+330
-1745
attach.dart
packages/flutter_tools/lib/src/commands/attach.dart
+12
-71
drive.dart
packages/flutter_tools/lib/src/commands/drive.dart
+2
-25
run.dart
packages/flutter_tools/lib/src/commands/run.dart
+1
-1
context_runner.dart
packages/flutter_tools/lib/src/context_runner.dart
+1
-1
device.dart
packages/flutter_tools/lib/src/device.dart
+1
-11
devices.dart
packages/flutter_tools/lib/src/ios/devices.dart
+19
-65
xcdevice.dart
packages/flutter_tools/lib/src/macos/xcdevice.dart
+7
-9
mdns_discovery.dart
packages/flutter_tools/lib/src/mdns_discovery.dart
+106
-388
flutter_command.dart
packages/flutter_tools/lib/src/runner/flutter_command.dart
+1
-1
attach_test.dart
...utter_tools/test/commands.shard/hermetic/attach_test.dart
+6
-328
drive_test.dart
...lutter_tools/test/commands.shard/hermetic/drive_test.dart
+0
-101
device_test.dart
packages/flutter_tools/test/general.shard/device_test.dart
+0
-48
ios_device_start_prebuilt_test.dart
...est/general.shard/ios/ios_device_start_prebuilt_test.dart
+6
-75
xcode_test.dart
...es/flutter_tools/test/general.shard/macos/xcode_test.dart
+3
-7
mdns_discovery_test.dart
...flutter_tools/test/general.shard/mdns_discovery_test.dart
+165
-614
No files found.
packages/flutter_tools/lib/src/commands/attach.dart
View file @
cbf2e168
...
@@ -24,7 +24,6 @@ import '../device.dart';
...
@@ -24,7 +24,6 @@ import '../device.dart';
import
'../device_port_forwarder.dart'
;
import
'../device_port_forwarder.dart'
;
import
'../fuchsia/fuchsia_device.dart'
;
import
'../fuchsia/fuchsia_device.dart'
;
import
'../ios/devices.dart'
;
import
'../ios/devices.dart'
;
import
'../ios/iproxy.dart'
;
import
'../ios/simulators.dart'
;
import
'../ios/simulators.dart'
;
import
'../macos/macos_ipad_device.dart'
;
import
'../macos/macos_ipad_device.dart'
;
import
'../mdns_discovery.dart'
;
import
'../mdns_discovery.dart'
;
...
@@ -230,7 +229,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
...
@@ -230,7 +229,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
}
}
if
(
debugPort
!=
null
&&
debugUri
!=
null
)
{
if
(
debugPort
!=
null
&&
debugUri
!=
null
)
{
throwToolExit
(
throwToolExit
(
'Either --debug
-port or --debug-url
can be provided, not both.'
);
'Either --debug
Port or --debugUri
can be provided, not both.'
);
}
}
if
(
userIdentifier
!=
null
)
{
if
(
userIdentifier
!=
null
)
{
...
@@ -283,9 +282,8 @@ known, it can be explicitly provided to attach via the command-line, e.g.
...
@@ -283,9 +282,8 @@ known, it can be explicitly provided to attach via the command-line, e.g.
final
String
ipv6Loopback
=
InternetAddress
.
loopbackIPv6
.
address
;
final
String
ipv6Loopback
=
InternetAddress
.
loopbackIPv6
.
address
;
final
String
ipv4Loopback
=
InternetAddress
.
loopbackIPv4
.
address
;
final
String
ipv4Loopback
=
InternetAddress
.
loopbackIPv4
.
address
;
final
String
hostname
=
usesIpv6
?
ipv6Loopback
:
ipv4Loopback
;
final
String
hostname
=
usesIpv6
?
ipv6Loopback
:
ipv4Loopback
;
final
bool
isNetworkDevice
=
(
device
is
IOSDevice
)
&&
device
.
interfaceType
==
IOSDeviceConnectionInterface
.
network
;
if
(
(
debugPort
==
null
&&
debugUri
==
null
)
||
isNetworkDevice
)
{
if
(
debugPort
==
null
&&
debugUri
==
null
)
{
if
(
device
is
FuchsiaDevice
)
{
if
(
device
is
FuchsiaDevice
)
{
final
String
module
=
stringArgDeprecated
(
'module'
)!;
final
String
module
=
stringArgDeprecated
(
'module'
)!;
if
(
module
==
null
)
{
if
(
module
==
null
)
{
...
@@ -305,73 +303,16 @@ known, it can be explicitly provided to attach via the command-line, e.g.
...
@@ -305,73 +303,16 @@ known, it can be explicitly provided to attach via the command-line, e.g.
rethrow
;
rethrow
;
}
}
}
else
if
((
device
is
IOSDevice
)
||
(
device
is
IOSSimulator
)
||
(
device
is
MacOSDesignedForIPadDevice
))
{
}
else
if
((
device
is
IOSDevice
)
||
(
device
is
IOSSimulator
)
||
(
device
is
MacOSDesignedForIPadDevice
))
{
// Protocol Discovery relies on logging. On iOS earlier than 13, logging is gathered using syslog.
final
Uri
?
uriFromMdns
=
// syslog is not available for iOS 13+. For iOS 13+, Protocol Discovery gathers logs from the VMService.
await
MDnsObservatoryDiscovery
.
instance
!.
getObservatoryUri
(
// Since we don't have access to the VMService yet, Protocol Discovery cannot be used for iOS 13+.
// Also, network devices must be found using mDNS and cannot use Protocol Discovery.
final
bool
compatibleWithProtocolDiscovery
=
(
device
is
IOSDevice
)
&&
device
.
majorSdkVersion
<
IOSDeviceLogReader
.
minimumUniversalLoggingSdkVersion
&&
!
isNetworkDevice
;
_logger
.
printStatus
(
'Waiting for a connection from Flutter on
${device.name}
...'
);
final
Status
discoveryStatus
=
_logger
.
startSpinner
(
timeout:
const
Duration
(
seconds:
30
),
slowWarningCallback:
()
{
// If relying on mDNS to find Dart VM Service, remind the user to allow local network permissions.
if
(!
compatibleWithProtocolDiscovery
)
{
return
'The Dart VM Service was not discovered after 30 seconds. This is taking much longer than expected...
\n\n
'
'Click "Allow" to the prompt asking if you would like to find and connect devices on your local network. '
'If you selected "Don
\'
t Allow", you can turn it on in Settings > Your App Name > Local Network. '
"If you don't see your app in the Settings, uninstall the app and rerun to see the prompt again.
\n
"
;
}
return
'The Dart VM Service was not discovered after 30 seconds. This is taking much longer than expected...
\n
'
;
},
);
int
?
devicePort
;
if
(
debugPort
!=
null
)
{
devicePort
=
debugPort
;
}
else
if
(
debugUri
!=
null
)
{
devicePort
=
debugUri
?.
port
;
}
else
if
(
deviceVmservicePort
!=
null
)
{
devicePort
=
deviceVmservicePort
;
}
final
Future
<
Uri
?>
mDNSDiscoveryFuture
=
MDnsVmServiceDiscovery
.
instance
!.
getVMServiceUriForAttach
(
appId
,
appId
,
device
,
device
,
usesIpv6:
usesIpv6
,
usesIpv6:
usesIpv6
,
isNetworkDevice:
isNetworkDevice
,
deviceVmservicePort:
deviceVmservicePort
,
deviceVmservicePort:
devicePort
,
);
);
observatoryUri
=
uriFromMdns
==
null
Future
<
Uri
?>?
protocolDiscoveryFuture
;
if
(
compatibleWithProtocolDiscovery
)
{
final
ProtocolDiscovery
vmServiceDiscovery
=
ProtocolDiscovery
.
observatory
(
device
.
getLogReader
(),
portForwarder:
device
.
portForwarder
,
ipv6:
ipv6
!,
devicePort:
devicePort
,
hostPort:
hostVmservicePort
,
logger:
_logger
,
);
protocolDiscoveryFuture
=
vmServiceDiscovery
.
uri
;
}
final
Uri
?
foundUrl
;
if
(
protocolDiscoveryFuture
==
null
)
{
foundUrl
=
await
mDNSDiscoveryFuture
;
}
else
{
foundUrl
=
await
Future
.
any
(
<
Future
<
Uri
?>>[
mDNSDiscoveryFuture
,
protocolDiscoveryFuture
]
);
}
discoveryStatus
.
stop
();
observatoryUri
=
foundUrl
==
null
?
null
?
null
:
Stream
<
Uri
>.
value
(
foundUrl
).
asBroadcastStream
();
:
Stream
<
Uri
>.
value
(
uriFromMdns
).
asBroadcastStream
();
}
}
// If MDNS discovery fails or we're not on iOS, fallback to ProtocolDiscovery.
// If MDNS discovery fails or we're not on iOS, fallback to ProtocolDiscovery.
if
(
observatoryUri
==
null
)
{
if
(
observatoryUri
==
null
)
{
...
@@ -394,7 +335,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
...
@@ -394,7 +335,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
}
else
{
}
else
{
observatoryUri
=
Stream
<
Uri
>
observatoryUri
=
Stream
<
Uri
>
.
fromFuture
(
.
fromFuture
(
build
VMService
Uri
(
build
Observatory
Uri
(
device
,
device
,
debugUri
?.
host
??
hostname
,
debugUri
?.
host
??
hostname
,
debugPort
??
debugUri
!.
port
,
debugPort
??
debugUri
!.
port
,
...
...
packages/flutter_tools/lib/src/commands/drive.dart
View file @
cbf2e168
...
@@ -4,7 +4,6 @@
...
@@ -4,7 +4,6 @@
import
'dart:async'
;
import
'dart:async'
;
import
'package:args/args.dart'
;
import
'package:meta/meta.dart'
;
import
'package:meta/meta.dart'
;
import
'package:package_config/package_config_types.dart'
;
import
'package:package_config/package_config_types.dart'
;
...
@@ -22,8 +21,6 @@ import '../dart/package_map.dart';
...
@@ -22,8 +21,6 @@ import '../dart/package_map.dart';
import
'../device.dart'
;
import
'../device.dart'
;
import
'../drive/drive_service.dart'
;
import
'../drive/drive_service.dart'
;
import
'../globals.dart'
as
globals
;
import
'../globals.dart'
as
globals
;
import
'../ios/devices.dart'
;
import
'../ios/iproxy.dart'
;
import
'../resident_runner.dart'
;
import
'../resident_runner.dart'
;
import
'../runner/flutter_command.dart'
show
FlutterCommandCategory
,
FlutterCommandResult
,
FlutterOptions
;
import
'../runner/flutter_command.dart'
show
FlutterCommandCategory
,
FlutterCommandResult
,
FlutterOptions
;
import
'../web/web_device.dart'
;
import
'../web/web_device.dart'
;
...
@@ -206,27 +203,6 @@ class DriveCommand extends RunCommandBase {
...
@@ -206,27 +203,6 @@ class DriveCommand extends RunCommandBase {
@override
@override
bool
get
cachePubGet
=>
false
;
bool
get
cachePubGet
=>
false
;
String
?
get
applicationBinaryPath
=>
stringArgDeprecated
(
FlutterOptions
.
kUseApplicationBinary
);
Future
<
Device
?>
get
targetedDevice
async
{
return
findTargetDevice
(
includeUnsupportedDevices:
applicationBinaryPath
==
null
);
}
// Network devices need `publish-port` to be enabled because it requires mDNS.
// If the flag wasn't provided as an actual argument and it's a network device,
// change it to be enabled.
@override
Future
<
bool
>
get
disablePortPublication
async
{
final
ArgResults
?
localArgResults
=
argResults
;
final
Device
?
device
=
await
targetedDevice
;
final
bool
isNetworkDevice
=
device
is
IOSDevice
&&
device
.
interfaceType
==
IOSDeviceConnectionInterface
.
network
;
if
(
isNetworkDevice
&&
localArgResults
!=
null
&&
!
localArgResults
.
wasParsed
(
'publish-port'
))
{
_logger
.
printTrace
(
'Network device is being used. Changing `publish-port` to be enabled.'
);
return
false
;
}
return
!
boolArgDeprecated
(
'publish-port'
);
}
@override
@override
Future
<
void
>
validateCommand
()
async
{
Future
<
void
>
validateCommand
()
async
{
if
(
userIdentifier
!=
null
)
{
if
(
userIdentifier
!=
null
)
{
...
@@ -247,7 +223,8 @@ class DriveCommand extends RunCommandBase {
...
@@ -247,7 +223,8 @@ class DriveCommand extends RunCommandBase {
if
(
await
_fileSystem
.
type
(
testFile
)
!=
FileSystemEntityType
.
file
)
{
if
(
await
_fileSystem
.
type
(
testFile
)
!=
FileSystemEntityType
.
file
)
{
throwToolExit
(
'Test file not found:
$testFile
'
);
throwToolExit
(
'Test file not found:
$testFile
'
);
}
}
final
Device
?
device
=
await
targetedDevice
;
final
String
?
applicationBinaryPath
=
stringArgDeprecated
(
FlutterOptions
.
kUseApplicationBinary
);
final
Device
?
device
=
await
findTargetDevice
(
includeUnsupportedDevices:
applicationBinaryPath
==
null
);
if
(
device
==
null
)
{
if
(
device
==
null
)
{
throwToolExit
(
null
);
throwToolExit
(
null
);
}
}
...
...
packages/flutter_tools/lib/src/commands/run.dart
View file @
cbf2e168
...
@@ -254,7 +254,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
...
@@ -254,7 +254,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
purgePersistentCache:
purgePersistentCache
,
purgePersistentCache:
purgePersistentCache
,
deviceVmServicePort:
deviceVmservicePort
,
deviceVmServicePort:
deviceVmservicePort
,
hostVmServicePort:
hostVmservicePort
,
hostVmServicePort:
hostVmservicePort
,
disablePortPublication:
await
disablePortPublication
,
disablePortPublication:
disablePortPublication
,
ddsPort:
ddsPort
,
ddsPort:
ddsPort
,
devToolsServerAddress:
devToolsServerAddress
,
devToolsServerAddress:
devToolsServerAddress
,
verboseSystemLogs:
boolArgDeprecated
(
'verbose-system-logs'
),
verboseSystemLogs:
boolArgDeprecated
(
'verbose-system-logs'
),
...
...
packages/flutter_tools/lib/src/context_runner.dart
View file @
cbf2e168
...
@@ -275,7 +275,7 @@ Future<T> runInContext<T>(
...
@@ -275,7 +275,7 @@ Future<T> runInContext<T>(
featureFlags:
featureFlags
,
featureFlags:
featureFlags
,
platform:
globals
.
platform
,
platform:
globals
.
platform
,
),
),
MDns
VmServiceDiscovery:
()
=>
MDnsVmService
Discovery
(
MDns
ObservatoryDiscovery:
()
=>
MDnsObservatory
Discovery
(
logger:
globals
.
logger
,
logger:
globals
.
logger
,
flutterUsage:
globals
.
flutterUsage
,
flutterUsage:
globals
.
flutterUsage
,
),
),
...
...
packages/flutter_tools/lib/src/device.dart
View file @
cbf2e168
...
@@ -17,7 +17,6 @@ import 'base/utils.dart';
...
@@ -17,7 +17,6 @@ import 'base/utils.dart';
import
'build_info.dart'
;
import
'build_info.dart'
;
import
'devfs.dart'
;
import
'devfs.dart'
;
import
'device_port_forwarder.dart'
;
import
'device_port_forwarder.dart'
;
import
'ios/iproxy.dart'
;
import
'project.dart'
;
import
'project.dart'
;
import
'vmservice.dart'
;
import
'vmservice.dart'
;
...
@@ -918,13 +917,7 @@ class DebuggingOptions {
...
@@ -918,13 +917,7 @@ class DebuggingOptions {
/// * https://github.com/dart-lang/sdk/blob/main/sdk/lib/html/doc/NATIVE_NULL_ASSERTIONS.md
/// * https://github.com/dart-lang/sdk/blob/main/sdk/lib/html/doc/NATIVE_NULL_ASSERTIONS.md
final
bool
nativeNullAssertions
;
final
bool
nativeNullAssertions
;
List
<
String
>
getIOSLaunchArguments
(
List
<
String
>
getIOSLaunchArguments
(
EnvironmentType
environmentType
,
String
?
route
,
Map
<
String
,
Object
?>
platformArgs
)
{
EnvironmentType
environmentType
,
String
?
route
,
Map
<
String
,
Object
?>
platformArgs
,
{
bool
ipv6
=
false
,
IOSDeviceConnectionInterface
interfaceType
=
IOSDeviceConnectionInterface
.
none
})
{
final
String
dartVmFlags
=
computeDartVmFlags
(
this
);
final
String
dartVmFlags
=
computeDartVmFlags
(
this
);
return
<
String
>[
return
<
String
>[
if
(
enableDartProfiling
)
'--enable-dart-profiling'
,
if
(
enableDartProfiling
)
'--enable-dart-profiling'
,
...
@@ -961,9 +954,6 @@ class DebuggingOptions {
...
@@ -961,9 +954,6 @@ class DebuggingOptions {
// Use the suggested host port.
// Use the suggested host port.
if
(
environmentType
==
EnvironmentType
.
simulator
&&
hostVmServicePort
!=
null
)
if
(
environmentType
==
EnvironmentType
.
simulator
&&
hostVmServicePort
!=
null
)
'--observatory-port=
$hostVmServicePort
'
,
'--observatory-port=
$hostVmServicePort
'
,
// Tell the observatory to listen on all interfaces, don't restrict to the loopback.
if
(
interfaceType
==
IOSDeviceConnectionInterface
.
network
)
'--observatory-host=
${ipv6 ? '::0' : '0.0.0.0'}
'
,
];
];
}
}
...
...
packages/flutter_tools/lib/src/ios/devices.dart
View file @
cbf2e168
...
@@ -9,7 +9,6 @@ import 'package:process/process.dart';
...
@@ -9,7 +9,6 @@ import 'package:process/process.dart';
import
'package:vm_service/vm_service.dart'
as
vm_service
;
import
'package:vm_service/vm_service.dart'
as
vm_service
;
import
'../application_package.dart'
;
import
'../application_package.dart'
;
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/io.dart'
;
import
'../base/logger.dart'
;
import
'../base/logger.dart'
;
...
@@ -22,7 +21,6 @@ import '../device.dart';
...
@@ -22,7 +21,6 @@ import '../device.dart';
import
'../device_port_forwarder.dart'
;
import
'../device_port_forwarder.dart'
;
import
'../globals.dart'
as
globals
;
import
'../globals.dart'
as
globals
;
import
'../macos/xcdevice.dart'
;
import
'../macos/xcdevice.dart'
;
import
'../mdns_discovery.dart'
;
import
'../project.dart'
;
import
'../project.dart'
;
import
'../protocol_discovery.dart'
;
import
'../protocol_discovery.dart'
;
import
'../vmservice.dart'
;
import
'../vmservice.dart'
;
...
@@ -191,6 +189,15 @@ class IOSDevice extends Device {
...
@@ -191,6 +189,15 @@ class IOSDevice extends Device {
return
majorVersionString
!=
null
?
int
.
tryParse
(
majorVersionString
)
??
0
:
0
;
return
majorVersionString
!=
null
?
int
.
tryParse
(
majorVersionString
)
??
0
:
0
;
}
}
@override
bool
get
supportsHotReload
=>
interfaceType
==
IOSDeviceConnectionInterface
.
usb
;
@override
bool
get
supportsHotRestart
=>
interfaceType
==
IOSDeviceConnectionInterface
.
usb
;
@override
bool
get
supportsFlutterExit
=>
interfaceType
==
IOSDeviceConnectionInterface
.
usb
;
@override
@override
final
String
name
;
final
String
name
;
...
@@ -311,11 +318,7 @@ class IOSDevice extends Device {
...
@@ -311,11 +318,7 @@ class IOSDevice extends Device {
@visibleForTesting
Duration
?
discoveryTimeout
,
@visibleForTesting
Duration
?
discoveryTimeout
,
})
async
{
})
async
{
String
?
packageId
;
String
?
packageId
;
if
(
interfaceType
==
IOSDeviceConnectionInterface
.
network
&&
debuggingOptions
.
debuggingEnabled
&&
debuggingOptions
.
disablePortPublication
)
{
throwToolExit
(
'Cannot start app on wirelessly tethered iOS device. Try running again with the --publish-port flag'
);
}
if
(!
prebuiltApplication
)
{
if
(!
prebuiltApplication
)
{
_logger
.
printTrace
(
'Building
${package.name}
for
$id
'
);
_logger
.
printTrace
(
'Building
${package.name}
for
$id
'
);
...
@@ -350,10 +353,8 @@ class IOSDevice extends Device {
...
@@ -350,10 +353,8 @@ class IOSDevice extends Device {
EnvironmentType
.
physical
,
EnvironmentType
.
physical
,
route
,
route
,
platformArgs
,
platformArgs
,
ipv6:
ipv6
,
interfaceType:
interfaceType
,
);
);
Status
startApp
Status
=
_logger
.
startProgress
(
final
Status
install
Status
=
_logger
.
startProgress
(
'Installing and launching...'
,
'Installing and launching...'
,
);
);
try
{
try
{
...
@@ -378,10 +379,9 @@ class IOSDevice extends Device {
...
@@ -378,10 +379,9 @@ class IOSDevice extends Device {
deviceLogReader
.
debuggerStream
=
iosDeployDebugger
;
deviceLogReader
.
debuggerStream
=
iosDeployDebugger
;
}
}
}
}
// Don't port foward if debugging with a network device.
observatoryDiscovery
=
ProtocolDiscovery
.
observatory
(
observatoryDiscovery
=
ProtocolDiscovery
.
observatory
(
deviceLogReader
,
deviceLogReader
,
portForwarder:
interfaceType
==
IOSDeviceConnectionInterface
.
network
?
null
:
portForwarder
,
portForwarder:
portForwarder
,
hostPort:
debuggingOptions
.
hostVmServicePort
,
hostPort:
debuggingOptions
.
hostVmServicePort
,
devicePort:
debuggingOptions
.
deviceVmServicePort
,
devicePort:
debuggingOptions
.
deviceVmServicePort
,
ipv6:
ipv6
,
ipv6:
ipv6
,
...
@@ -412,59 +412,12 @@ class IOSDevice extends Device {
...
@@ -412,59 +412,12 @@ class IOSDevice extends Device {
return
LaunchResult
.
succeeded
();
return
LaunchResult
.
succeeded
();
}
}
_logger
.
printTrace
(
'Application launched on the device. Waiting for Dart VM Service url.'
);
_logger
.
printTrace
(
'Application launched on the device. Waiting for observatory url.'
);
final
Timer
timer
=
Timer
(
discoveryTimeout
??
const
Duration
(
seconds:
30
),
()
{
final
int
defaultTimeout
=
interfaceType
==
IOSDeviceConnectionInterface
.
network
?
45
:
30
;
_logger
.
printError
(
'iOS Observatory not discovered after 30 seconds. This is taking much longer than expected...'
);
final
Timer
timer
=
Timer
(
discoveryTimeout
??
Duration
(
seconds:
defaultTimeout
),
()
{
_logger
.
printError
(
'The Dart VM Service was not discovered after
$defaultTimeout
seconds. This is taking much longer than expected...'
);
// If debugging with a wireless device and the timeout is reached, remind the
// user to allow local network permissions.
if
(
interfaceType
==
IOSDeviceConnectionInterface
.
network
)
{
_logger
.
printError
(
'
\n
Click "Allow" to the prompt asking if you would like to find and connect devices on your local network. '
'This is required for wireless debugging. If you selected "Don
\'
t Allow", '
'you can turn it on in Settings > Your App Name > Local Network. '
"If you don't see your app in the Settings, uninstall the app and rerun to see the prompt again."
);
}
else
{
iosDeployDebugger
?.
pauseDumpBacktraceResume
();
iosDeployDebugger
?.
pauseDumpBacktraceResume
();
}
});
});
final
Uri
?
localUri
=
await
observatoryDiscovery
?.
uri
;
Uri
?
localUri
;
if
(
interfaceType
==
IOSDeviceConnectionInterface
.
network
)
{
// Wait for Dart VM Service to start up.
final
Uri
?
serviceURL
=
await
observatoryDiscovery
?.
uri
;
if
(
serviceURL
==
null
)
{
await
iosDeployDebugger
?.
stopAndDumpBacktrace
();
return
LaunchResult
.
failed
();
}
// If Dart VM Service URL with the device IP is not found within 5 seconds,
// change the status message to prompt users to click Allow. Wait 5 seconds because it
// should only show this message if they have not already approved the permissions.
// MDnsVmServiceDiscovery usually takes less than 5 seconds to find it.
final
Timer
mDNSLookupTimer
=
Timer
(
const
Duration
(
seconds:
5
),
()
{
startAppStatus
.
stop
();
startAppStatus
=
_logger
.
startProgress
(
'Waiting for approval of local network permissions...'
,
);
});
// Get Dart VM Service URL with the device IP as the host.
localUri
=
await
MDnsVmServiceDiscovery
.
instance
!.
getVMServiceUriForLaunch
(
packageId
,
this
,
usesIpv6:
ipv6
,
deviceVmservicePort:
serviceURL
.
port
,
isNetworkDevice:
true
,
);
mDNSLookupTimer
.
cancel
();
}
else
{
localUri
=
await
observatoryDiscovery
?.
uri
;
}
timer
.
cancel
();
timer
.
cancel
();
if
(
localUri
==
null
)
{
if
(
localUri
==
null
)
{
await
iosDeployDebugger
?.
stopAndDumpBacktrace
();
await
iosDeployDebugger
?.
stopAndDumpBacktrace
();
...
@@ -476,7 +429,7 @@ class IOSDevice extends Device {
...
@@ -476,7 +429,7 @@ class IOSDevice extends Device {
_logger
.
printError
(
e
.
message
);
_logger
.
printError
(
e
.
message
);
return
LaunchResult
.
failed
();
return
LaunchResult
.
failed
();
}
finally
{
}
finally
{
startApp
Status
.
stop
();
install
Status
.
stop
();
}
}
}
}
...
@@ -616,6 +569,7 @@ String decodeSyslog(String line) {
...
@@ -616,6 +569,7 @@ String decodeSyslog(String line) {
}
}
}
}
@visibleForTesting
class
IOSDeviceLogReader
extends
DeviceLogReader
{
class
IOSDeviceLogReader
extends
DeviceLogReader
{
IOSDeviceLogReader
.
_
(
IOSDeviceLogReader
.
_
(
this
.
_iMobileDevice
,
this
.
_iMobileDevice
,
...
...
packages/flutter_tools/lib/src/macos/xcdevice.dart
View file @
cbf2e168
...
@@ -227,16 +227,8 @@ class XCDevice {
...
@@ -227,16 +227,8 @@ class XCDevice {
/// [timeout] defaults to 2 seconds.
/// [timeout] defaults to 2 seconds.
Future
<
List
<
IOSDevice
>>
getAvailableIOSDevices
({
Duration
?
timeout
})
async
{
Future
<
List
<
IOSDevice
>>
getAvailableIOSDevices
({
Duration
?
timeout
})
async
{
Status
?
loadDevicesStatus
;
if
(
timeout
!=
null
&&
timeout
.
inSeconds
>
2
)
{
loadDevicesStatus
=
_logger
.
startProgress
(
'Loading devices...'
,
);
}
final
List
<
Object
>?
allAvailableDevices
=
await
_getAllDevices
(
timeout:
timeout
??
const
Duration
(
seconds:
2
));
final
List
<
Object
>?
allAvailableDevices
=
await
_getAllDevices
(
timeout:
timeout
??
const
Duration
(
seconds:
2
));
if
(
loadDevicesStatus
!=
null
)
{
loadDevicesStatus
.
stop
();
}
if
(
allAvailableDevices
==
null
)
{
if
(
allAvailableDevices
==
null
)
{
return
const
<
IOSDevice
>[];
return
const
<
IOSDevice
>[];
}
}
...
@@ -313,6 +305,12 @@ class XCDevice {
...
@@ -313,6 +305,12 @@ class XCDevice {
final
IOSDeviceConnectionInterface
interface
=
_interfaceType
(
device
);
final
IOSDeviceConnectionInterface
interface
=
_interfaceType
(
device
);
// Only support USB devices, skip "network" interface (Xcode > Window > Devices and Simulators > Connect via network).
// TODO(jmagman): Remove this check once wirelessly detected devices can be observed and attached, https://github.com/flutter/flutter/issues/15072.
if
(
interface
!=
IOSDeviceConnectionInterface
.
usb
)
{
continue
;
}
String
?
sdkVersion
=
_sdkVersion
(
device
);
String
?
sdkVersion
=
_sdkVersion
(
device
);
if
(
sdkVersion
!=
null
)
{
if
(
sdkVersion
!=
null
)
{
...
...
packages/flutter_tools/lib/src/mdns_discovery.dart
View file @
cbf2e168
...
@@ -13,278 +13,114 @@ import 'build_info.dart';
...
@@ -13,278 +13,114 @@ import 'build_info.dart';
import
'device.dart'
;
import
'device.dart'
;
import
'reporting/reporting.dart'
;
import
'reporting/reporting.dart'
;
/// A wrapper around [MDnsClient] to find a Dart
VM Service
instance.
/// A wrapper around [MDnsClient] to find a Dart
observatory
instance.
class
MDns
VmService
Discovery
{
class
MDns
Observatory
Discovery
{
/// Creates a new [MDns
VmService
Discovery] object.
/// Creates a new [MDns
Observatory
Discovery] object.
///
///
/// The [_client] parameter will be defaulted to a new [MDnsClient] if null.
/// The [_client] parameter will be defaulted to a new [MDnsClient] if null.
MDnsVmServiceDiscovery
({
/// The [applicationId] parameter may be null, and can be used to
/// automatically select which application to use if multiple are advertising
/// Dart observatory ports.
MDnsObservatoryDiscovery
({
MDnsClient
?
mdnsClient
,
MDnsClient
?
mdnsClient
,
MDnsClient
?
preliminaryMDnsClient
,
required
Logger
logger
,
required
Logger
logger
,
required
Usage
flutterUsage
,
required
Usage
flutterUsage
,
})
:
_client
=
mdnsClient
??
MDnsClient
(),
}):
_client
=
mdnsClient
??
MDnsClient
(),
_preliminaryClient
=
preliminaryMDnsClient
,
_logger
=
logger
,
_logger
=
logger
,
_flutterUsage
=
flutterUsage
;
_flutterUsage
=
flutterUsage
;
final
MDnsClient
_client
;
final
MDnsClient
_client
;
// Used when discovering VM services with `queryForAttach` to do a preliminary
// check for already running services so that results are not cached in _client.
final
MDnsClient
?
_preliminaryClient
;
final
Logger
_logger
;
final
Logger
_logger
;
final
Usage
_flutterUsage
;
final
Usage
_flutterUsage
;
@visibleForTesting
@visibleForTesting
static
const
String
dart
VmService
Name
=
'_dartobservatory._tcp.local'
;
static
const
String
dart
Observatory
Name
=
'_dartobservatory._tcp.local'
;
static
MDns
VmServiceDiscovery
?
get
instance
=>
context
.
get
<
MDnsVmService
Discovery
>();
static
MDns
ObservatoryDiscovery
?
get
instance
=>
context
.
get
<
MDnsObservatory
Discovery
>();
/// Executes an mDNS query for Dart VM Services.
/// Executes an mDNS query for a Dart Observatory.
/// Checks for services that have already been launched.
/// If none are found, it will listen for new services to become active
/// and return the first it finds that match the parameters.
///
///
/// The [applicationId] parameter may be used to specify which application
/// The [applicationId] parameter may be used to specify which application
/// to find. For Android, it refers to the package name; on iOS, it refers to
/// to find. For Android, it refers to the package name; on iOS, it refers to
/// the bundle ID.
/// the bundle ID.
///
///
/// The [deviceVmservicePort] parameter may be used to specify which port
/// If it is not null, this method will find the port and authentication code
/// to find.
/// of the Dart Observatory for that application. If it cannot find a Dart
///
/// Observatory matching that application identifier, it will call
/// The [isNetworkDevice] parameter flags whether to get the device IP
/// [throwToolExit].
/// and the [ipv6] parameter flags whether to get an iPv6 address
/// (otherwise it will get iPv4).
///
/// The [timeout] parameter determines how long to continue to wait for
/// services to become active.
///
/// If [applicationId] is not null, this method will find the port and authentication code
/// of the Dart VM Service for that application. If it cannot find a service matching
/// that application identifier after the [timeout], it will call [throwToolExit].
///
/// If [applicationId] is null and there are multiple Dart VM Services available,
/// the user will be prompted with a list of available services with the respective
/// app-id and device-vmservice-port to use and asked to select one.
///
/// If it is null and there is only one available or it's the first found instance
/// of Dart VM Service, it will return that instance's information regardless of
/// what application the service instance is for.
@visibleForTesting
Future
<
MDnsVmServiceDiscoveryResult
?>
queryForAttach
({
String
?
applicationId
,
int
?
deviceVmservicePort
,
bool
ipv6
=
false
,
bool
isNetworkDevice
=
false
,
Duration
timeout
=
const
Duration
(
minutes:
10
),
})
async
{
// Poll for 5 seconds to see if there are already services running.
// Use a new instance of MDnsClient so results don't get cached in _client.
// If no results are found, poll for a longer duration to wait for connections.
// If more than 1 result is found, throw an error since it can't be determined which to pick.
// If only one is found, return it.
final
List
<
MDnsVmServiceDiscoveryResult
>
results
=
await
_pollingVmService
(
_preliminaryClient
??
MDnsClient
(),
applicationId:
applicationId
,
deviceVmservicePort:
deviceVmservicePort
,
ipv6:
ipv6
,
isNetworkDevice:
isNetworkDevice
,
timeout:
const
Duration
(
seconds:
5
),
);
if
(
results
.
isEmpty
)
{
return
firstMatchingVmService
(
_client
,
applicationId:
applicationId
,
deviceVmservicePort:
deviceVmservicePort
,
ipv6:
ipv6
,
isNetworkDevice:
isNetworkDevice
,
timeout:
timeout
,
);
}
else
if
(
results
.
length
>
1
)
{
final
StringBuffer
buffer
=
StringBuffer
();
buffer
.
writeln
(
'There are multiple Dart VM Services available.'
);
buffer
.
writeln
(
'Rerun this command with one of the following passed in as the app-id and device-vmservice-port:'
);
buffer
.
writeln
();
for
(
final
MDnsVmServiceDiscoveryResult
result
in
results
)
{
buffer
.
writeln
(
' flutter attach --app-id "
${result.domainName.replaceAll('.$dartVmServiceName', '')}
" --device-vmservice-port
${result.port}
'
);
}
throwToolExit
(
buffer
.
toString
());
}
return
results
.
first
;
}
/// Executes an mDNS query for Dart VM Services.
/// Listens for new services to become active and returns the first it finds that
/// match the parameters.
///
/// The [applicationId] parameter must be set to specify which application
/// to find. For Android, it refers to the package name; on iOS, it refers to
/// the bundle ID.
///
/// The [deviceVmservicePort] parameter must be set to specify which port
/// to find.
///
/// [applicationId] and [deviceVmservicePort] are required for launch so that
/// if multiple flutter apps are running on different devices, it will
/// only match with the device running the desired app.
///
/// The [isNetworkDevice] parameter flags whether to get the device IP
/// and the [ipv6] parameter flags whether to get an iPv6 address
/// (otherwise it will get iPv4).
///
///
/// The [timeout] parameter determines how long to continue to wait for
/// If it is null and there are multiple ports available, the user will be
/// services to become active.
/// prompted with a list of available observatory ports and asked to select
/// one.
///
///
/// If a Dart VM Service matching the [applicationId] and [deviceVmservicePort]
/// If it is null and there is only one available instance of Observatory,
/// cannot be found after the [timeout], it will call [throwToolExit].
/// it will return that instance's information regardless of what application
/// the Observatory instance is for.
@visibleForTesting
@visibleForTesting
Future
<
MDnsVmServiceDiscoveryResult
?>
queryForLaunch
({
Future
<
MDnsObservatoryDiscoveryResult
?>
query
({
String
?
applicationId
,
int
?
deviceVmservicePort
})
async
{
required
String
applicationId
,
_logger
.
printTrace
(
'Checking for advertised Dart observatories...'
);
required
int
deviceVmservicePort
,
try
{
bool
ipv6
=
false
,
await
_client
.
start
();
bool
isNetworkDevice
=
false
,
final
List
<
PtrResourceRecord
>
pointerRecords
=
await
_client
Duration
timeout
=
const
Duration
(
minutes:
10
),
.
lookup
<
PtrResourceRecord
>(
})
async
{
ResourceRecordQuery
.
serverPointer
(
dartObservatoryName
),
// Query for a specific application and device port.
)
return
firstMatchingVmService
(
.
toList
();
_client
,
if
(
pointerRecords
.
isEmpty
)
{
applicationId:
applicationId
,
_logger
.
printTrace
(
'No pointer records found.'
);
deviceVmservicePort:
deviceVmservicePort
,
ipv6:
ipv6
,
isNetworkDevice:
isNetworkDevice
,
timeout:
timeout
,
);
}
/// Polls for Dart VM Services and returns the first it finds that match
/// the [applicationId]/[deviceVmservicePort] (if applicable).
/// Returns null if no results are found.
@visibleForTesting
Future
<
MDnsVmServiceDiscoveryResult
?>
firstMatchingVmService
(
MDnsClient
client
,
{
String
?
applicationId
,
int
?
deviceVmservicePort
,
bool
ipv6
=
false
,
bool
isNetworkDevice
=
false
,
Duration
timeout
=
const
Duration
(
minutes:
10
),
})
async
{
final
List
<
MDnsVmServiceDiscoveryResult
>
results
=
await
_pollingVmService
(
client
,
applicationId:
applicationId
,
deviceVmservicePort:
deviceVmservicePort
,
ipv6:
ipv6
,
isNetworkDevice:
isNetworkDevice
,
timeout:
timeout
,
quitOnFind:
true
,
);
if
(
results
.
isEmpty
)
{
return
null
;
return
null
;
}
}
return
results
.
first
;
// We have no guarantee that we won't get multiple hits from the same
}
// service on this.
final
Set
<
String
>
uniqueDomainNames
=
pointerRecords
Future
<
List
<
MDnsVmServiceDiscoveryResult
>>
_pollingVmService
(
.
map
<
String
>((
PtrResourceRecord
record
)
=>
record
.
domainName
)
MDnsClient
client
,
{
.
toSet
();
String
?
applicationId
,
int
?
deviceVmservicePort
,
bool
ipv6
=
false
,
bool
isNetworkDevice
=
false
,
required
Duration
timeout
,
bool
quitOnFind
=
false
,
})
async
{
_logger
.
printTrace
(
'Checking for advertised Dart VM Services...'
);
try
{
await
client
.
start
();
final
List
<
MDnsVmServiceDiscoveryResult
>
results
=
<
MDnsVmServiceDiscoveryResult
>[];
final
Set
<
String
>
uniqueDomainNames
=
<
String
>{};
// Listen for mDNS connections until timeout.
final
Stream
<
PtrResourceRecord
>
ptrResourceStream
=
client
.
lookup
<
PtrResourceRecord
>(
ResourceRecordQuery
.
serverPointer
(
dartVmServiceName
),
timeout:
timeout
);
await
for
(
final
PtrResourceRecord
ptr
in
ptrResourceStream
)
{
uniqueDomainNames
.
add
(
ptr
.
domainName
);
String
?
domainName
;
String
?
domainName
;
if
(
applicationId
!=
null
)
{
if
(
applicationId
!=
null
)
{
// If applicationId is set, only use records that match it
for
(
final
String
name
in
uniqueDomainNames
)
{
if
(
ptr
.
domainName
.
toLowerCase
().
startsWith
(
applicationId
.
toLowerCase
()))
{
if
(
name
.
toLowerCase
().
startsWith
(
applicationId
.
toLowerCase
()))
{
domainName
=
ptr
.
domainName
;
domainName
=
name
;
}
else
{
break
;
continue
;
}
}
}
if
(
domainName
==
null
)
{
throwToolExit
(
'Did not find a observatory port advertised for
$applicationId
.'
);
}
}
else
if
(
uniqueDomainNames
.
length
>
1
)
{
final
StringBuffer
buffer
=
StringBuffer
();
buffer
.
writeln
(
'There are multiple observatory ports available.'
);
buffer
.
writeln
(
'Rerun this command with one of the following passed in as the appId:'
);
buffer
.
writeln
();
for
(
final
String
uniqueDomainName
in
uniqueDomainNames
)
{
buffer
.
writeln
(
' flutter attach --app-id
${uniqueDomainName.replaceAll('.$dartObservatoryName', '')}
'
);
}
throwToolExit
(
buffer
.
toString
());
}
else
{
}
else
{
domainName
=
ptr
.
domainName
;
domainName
=
pointerRecords
[
0
]
.
domainName
;
}
}
_logger
.
printTrace
(
'Checking for available port on
$domainName
'
);
_logger
.
printTrace
(
'Checking for available port on
$domainName
'
);
final
List
<
SrvResourceRecord
>
srvRecords
=
await
client
// Here, if we get more than one, it should just be a duplicate.
final
List
<
SrvResourceRecord
>
srv
=
await
_client
.
lookup
<
SrvResourceRecord
>(
.
lookup
<
SrvResourceRecord
>(
ResourceRecordQuery
.
service
(
domainName
),
ResourceRecordQuery
.
service
(
domainName
),
)
)
.
toList
();
.
toList
();
if
(
srvRecords
.
isEmpty
)
{
if
(
srv
.
isEmpty
)
{
continue
;
return
null
;
}
// If more than one SrvResourceRecord found, it should just be a duplicate.
final
SrvResourceRecord
srvRecord
=
srvRecords
.
first
;
if
(
srvRecords
.
length
>
1
)
{
_logger
.
printWarning
(
'Unexpectedly found more than one Dart VM Service report for
$domainName
'
'- using first one (
${srvRecord.port}
).'
);
}
// If deviceVmservicePort is set, only use records that match it
if
(
deviceVmservicePort
!=
null
&&
srvRecord
.
port
!=
deviceVmservicePort
)
{
continue
;
}
// Get the IP address of the service if using a network device.
InternetAddress
?
ipAddress
;
if
(
isNetworkDevice
)
{
List
<
IPAddressResourceRecord
>
ipAddresses
=
await
client
.
lookup
<
IPAddressResourceRecord
>(
ipv6
?
ResourceRecordQuery
.
addressIPv6
(
srvRecord
.
target
)
:
ResourceRecordQuery
.
addressIPv4
(
srvRecord
.
target
),
)
.
toList
();
if
(
ipAddresses
.
isEmpty
)
{
throwToolExit
(
'Did not find IP for service
${srvRecord.target}
.'
);
}
// Filter out link-local addresses.
if
(
ipAddresses
.
length
>
1
)
{
ipAddresses
=
ipAddresses
.
where
((
IPAddressResourceRecord
element
)
=>
!
element
.
address
.
isLinkLocal
).
toList
();
}
ipAddress
=
ipAddresses
.
first
.
address
;
if
(
ipAddresses
.
length
>
1
)
{
_logger
.
printWarning
(
'Unexpectedly found more than one IP for Dart VM Service
${srvRecord.target}
'
'- using first one (
$ipAddress
).'
);
}
}
if
(
srv
.
length
>
1
)
{
_logger
.
printWarning
(
'Unexpectedly found more than one observatory report for
$domainName
'
'- using first one (
${srv.first.port}
).'
);
}
}
_logger
.
printTrace
(
'Checking for authentication code for
$domainName
'
);
_logger
.
printTrace
(
'Checking for authentication code for
$domainName
'
);
final
List
<
TxtResourceRecord
>
txt
=
await
client
final
List
<
TxtResourceRecord
>
txt
=
await
_
client
.
lookup
<
TxtResourceRecord
>(
.
lookup
<
TxtResourceRecord
>(
ResourceRecordQuery
.
text
(
domainName
),
ResourceRecordQuery
.
text
(
domainName
),
)
)
.
toList
();
.
toList
();
if
(
txt
==
null
||
txt
.
isEmpty
)
{
if
(
txt
==
null
||
txt
.
isEmpty
)
{
results
.
add
(
MDnsVmServiceDiscoveryResult
(
domainName
,
srvRecord
.
port
,
''
));
return
MDnsObservatoryDiscoveryResult
(
srv
.
first
.
port
,
''
);
if
(
quitOnFind
)
{
return
results
;
}
continue
;
}
}
const
String
authCodePrefix
=
'authCode='
;
const
String
authCodePrefix
=
'authCode='
;
String
?
raw
;
String
?
raw
;
...
@@ -295,145 +131,43 @@ class MDnsVmServiceDiscovery {
...
@@ -295,145 +131,43 @@ class MDnsVmServiceDiscovery {
}
}
}
}
if
(
raw
==
null
)
{
if
(
raw
==
null
)
{
results
.
add
(
MDnsVmServiceDiscoveryResult
(
domainName
,
srvRecord
.
port
,
''
));
return
MDnsObservatoryDiscoveryResult
(
srv
.
first
.
port
,
''
);
if
(
quitOnFind
)
{
return
results
;
}
continue
;
}
}
String
authCode
=
raw
.
substring
(
authCodePrefix
.
length
);
String
authCode
=
raw
.
substring
(
authCodePrefix
.
length
);
// The Dart VM Service
currently expects a trailing '/' as part of the
// The Observatory
currently expects a trailing '/' as part of the
// URI, otherwise an invalid authentication code response is given.
// URI, otherwise an invalid authentication code response is given.
if
(!
authCode
.
endsWith
(
'/'
))
{
if
(!
authCode
.
endsWith
(
'/'
))
{
authCode
+=
'/'
;
authCode
+=
'/'
;
}
}
return
MDnsObservatoryDiscoveryResult
(
srv
.
first
.
port
,
authCode
);
results
.
add
(
MDnsVmServiceDiscoveryResult
(
domainName
,
srvRecord
.
port
,
authCode
,
ipAddress:
ipAddress
));
if
(
quitOnFind
)
{
return
results
;
}
}
// If applicationId is set and quitOnFind is true and no results matching
// the applicationId were found but other results were found, throw an error.
if
(
applicationId
!=
null
&&
quitOnFind
&&
results
.
isEmpty
&&
uniqueDomainNames
.
isNotEmpty
)
{
String
message
=
'Did not find a Dart VM Service advertised for
$applicationId
'
;
if
(
deviceVmservicePort
!=
null
)
{
message
+=
' on port
$deviceVmservicePort
'
;
}
throwToolExit
(
'
$message
.'
);
}
return
results
;
}
finally
{
}
finally
{
client
.
stop
();
_
client
.
stop
();
}
}
}
}
/// Gets Dart VM Service Uri for `flutter attach`.
Future
<
Uri
?>
getObservatoryUri
(
String
?
applicationId
,
Device
device
,
{
/// Executes an mDNS query and waits until a Dart VM Service is found.
///
/// Differs from `getVMServiceUriForLaunch` because it can search for any available Dart VM Service.
/// Since [applicationId] and [deviceVmservicePort] are optional, it can either look for any service
/// or a specific service matching [applicationId]/[deviceVmservicePort].
/// It may find more than one service, which will throw an error listing the found services.
Future
<
Uri
?>
getVMServiceUriForAttach
(
String
?
applicationId
,
Device
device
,
{
bool
usesIpv6
=
false
,
bool
usesIpv6
=
false
,
int
?
hostVmservicePort
,
int
?
hostVmservicePort
,
int
?
deviceVmservicePort
,
int
?
deviceVmservicePort
,
bool
isNetworkDevice
=
false
,
Duration
timeout
=
const
Duration
(
minutes:
10
),
})
async
{
})
async
{
final
MDns
VmServiceDiscoveryResult
?
result
=
await
queryForAttach
(
final
MDns
ObservatoryDiscoveryResult
?
result
=
await
query
(
applicationId:
applicationId
,
applicationId:
applicationId
,
deviceVmservicePort:
deviceVmservicePort
,
deviceVmservicePort:
deviceVmservicePort
,
ipv6:
usesIpv6
,
isNetworkDevice:
isNetworkDevice
,
timeout:
timeout
,
);
);
return
_handleResult
(
result
,
device
,
applicationId:
applicationId
,
deviceVmservicePort:
deviceVmservicePort
,
hostVmservicePort:
hostVmservicePort
,
usesIpv6:
usesIpv6
,
isNetworkDevice:
isNetworkDevice
);
}
/// Gets Dart VM Service Uri for `flutter run`.
/// Executes an mDNS query and waits until the Dart VM Service service is found.
///
/// Differs from `getVMServiceUriForAttach` because it only searches for a specific service.
/// This is enforced by [applicationId] and [deviceVmservicePort] being required.
Future
<
Uri
?>
getVMServiceUriForLaunch
(
String
applicationId
,
Device
device
,
{
bool
usesIpv6
=
false
,
int
?
hostVmservicePort
,
required
int
deviceVmservicePort
,
bool
isNetworkDevice
=
false
,
Duration
timeout
=
const
Duration
(
minutes:
10
),
})
async
{
final
MDnsVmServiceDiscoveryResult
?
result
=
await
queryForLaunch
(
applicationId:
applicationId
,
deviceVmservicePort:
deviceVmservicePort
,
ipv6:
usesIpv6
,
isNetworkDevice:
isNetworkDevice
,
timeout:
timeout
,
);
return
_handleResult
(
result
,
device
,
applicationId:
applicationId
,
deviceVmservicePort:
deviceVmservicePort
,
hostVmservicePort:
hostVmservicePort
,
usesIpv6:
usesIpv6
,
isNetworkDevice:
isNetworkDevice
);
}
Future
<
Uri
?>
_handleResult
(
MDnsVmServiceDiscoveryResult
?
result
,
Device
device
,
{
String
?
applicationId
,
int
?
deviceVmservicePort
,
int
?
hostVmservicePort
,
bool
usesIpv6
=
false
,
bool
isNetworkDevice
=
false
,
})
async
{
if
(
result
==
null
)
{
if
(
result
==
null
)
{
await
_checkForIPv4LinkLocal
(
device
);
await
_checkForIPv4LinkLocal
(
device
);
return
null
;
return
null
;
}
}
final
String
host
;
final
InternetAddress
?
ipAddress
=
result
.
ipAddress
;
final
String
host
=
usesIpv6
if
(
isNetworkDevice
&&
ipAddress
!=
null
)
{
host
=
ipAddress
.
address
;
}
else
{
host
=
usesIpv6
?
InternetAddress
.
loopbackIPv6
.
address
?
InternetAddress
.
loopbackIPv6
.
address
:
InternetAddress
.
loopbackIPv4
.
address
;
:
InternetAddress
.
loopbackIPv4
.
address
;
}
return
buildObservatoryUri
(
return
buildVMServiceUri
(
device
,
device
,
host
,
host
,
result
.
port
,
result
.
port
,
hostVmservicePort
,
hostVmservicePort
,
result
.
authCode
,
result
.
authCode
,
isNetworkDevice
,
);
);
}
}
...
@@ -502,26 +236,18 @@ class MDnsVmServiceDiscovery {
...
@@ -502,26 +236,18 @@ class MDnsVmServiceDiscovery {
}
}
}
}
class
MDnsVmServiceDiscoveryResult
{
class
MDnsObservatoryDiscoveryResult
{
MDnsVmServiceDiscoveryResult
(
MDnsObservatoryDiscoveryResult
(
this
.
port
,
this
.
authCode
);
this
.
domainName
,
this
.
port
,
this
.
authCode
,
{
this
.
ipAddress
});
final
String
domainName
;
final
int
port
;
final
int
port
;
final
String
authCode
;
final
String
authCode
;
final
InternetAddress
?
ipAddress
;
}
}
Future
<
Uri
>
build
VMService
Uri
(
Future
<
Uri
>
build
Observatory
Uri
(
Device
device
,
Device
device
,
String
host
,
String
host
,
int
devicePort
,
[
int
devicePort
,
[
int
?
hostVmservicePort
,
int
?
hostVmservicePort
,
String
?
authCode
,
String
?
authCode
,
bool
isNetworkDevice
=
false
,
])
async
{
])
async
{
String
path
=
'/'
;
String
path
=
'/'
;
if
(
authCode
!=
null
)
{
if
(
authCode
!=
null
)
{
...
@@ -533,16 +259,8 @@ Future<Uri> buildVMServiceUri(
...
@@ -533,16 +259,8 @@ Future<Uri> buildVMServiceUri(
path
+=
'/'
;
path
+=
'/'
;
}
}
hostVmservicePort
??=
0
;
hostVmservicePort
??=
0
;
final
int
?
actualHostPort
=
hostVmservicePort
==
0
?
final
int
?
actualHostPort
;
if
(
isNetworkDevice
)
{
// When debugging with a network device, port forwarding is not required
// so just use the device's port.
actualHostPort
=
devicePort
;
}
else
{
actualHostPort
=
hostVmservicePort
==
0
?
await
device
.
portForwarder
?.
forward
(
devicePort
)
:
await
device
.
portForwarder
?.
forward
(
devicePort
)
:
hostVmservicePort
;
hostVmservicePort
;
}
return
Uri
(
scheme:
'http'
,
host:
host
,
port:
actualHostPort
,
path:
path
);
return
Uri
(
scheme:
'http'
,
host:
host
,
port:
actualHostPort
,
path:
path
);
}
}
packages/flutter_tools/lib/src/runner/flutter_command.dart
View file @
cbf2e168
...
@@ -569,7 +569,7 @@ abstract class FlutterCommand extends Command<void> {
...
@@ -569,7 +569,7 @@ abstract class FlutterCommand extends Command<void> {
);
);
}
}
Future
<
bool
>
get
disablePortPublication
async
=>
!
boolArgDeprecated
(
'publish-port'
);
bool
get
disablePortPublication
=>
!
boolArgDeprecated
(
'publish-port'
);
void
usesIpv6Flag
({
required
bool
verboseHelp
})
{
void
usesIpv6Flag
({
required
bool
verboseHelp
})
{
argParser
.
addFlag
(
ipv6Flag
,
argParser
.
addFlag
(
ipv6Flag
,
...
...
packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart
View file @
cbf2e168
...
@@ -23,7 +23,6 @@ import 'package:flutter_tools/src/device.dart';
...
@@ -23,7 +23,6 @@ import 'package:flutter_tools/src/device.dart';
import
'package:flutter_tools/src/device_port_forwarder.dart'
;
import
'package:flutter_tools/src/device_port_forwarder.dart'
;
import
'package:flutter_tools/src/ios/application_package.dart'
;
import
'package:flutter_tools/src/ios/application_package.dart'
;
import
'package:flutter_tools/src/ios/devices.dart'
;
import
'package:flutter_tools/src/ios/devices.dart'
;
import
'package:flutter_tools/src/ios/iproxy.dart'
;
import
'package:flutter_tools/src/macos/macos_ipad_device.dart'
;
import
'package:flutter_tools/src/macos/macos_ipad_device.dart'
;
import
'package:flutter_tools/src/mdns_discovery.dart'
;
import
'package:flutter_tools/src/mdns_discovery.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/project.dart'
;
...
@@ -84,7 +83,6 @@ void main() {
...
@@ -84,7 +83,6 @@ void main() {
group
(
'with one device and no specified target file'
,
()
{
group
(
'with one device and no specified target file'
,
()
{
const
int
devicePort
=
499
;
const
int
devicePort
=
499
;
const
int
hostPort
=
42
;
const
int
hostPort
=
42
;
final
int
future
=
DateTime
.
now
().
add
(
const
Duration
(
days:
1
)).
millisecondsSinceEpoch
;
late
FakeDeviceLogReader
fakeLogReader
;
late
FakeDeviceLogReader
fakeLogReader
;
late
RecordingPortForwarder
portForwarder
;
late
RecordingPortForwarder
portForwarder
;
...
@@ -104,17 +102,17 @@ void main() {
...
@@ -104,17 +102,17 @@ void main() {
fakeLogReader
.
dispose
();
fakeLogReader
.
dispose
();
});
});
testUsingContext
(
'succeeds with iOS device
with protocol discovery
'
,
()
async
{
testUsingContext
(
'succeeds with iOS device'
,
()
async
{
final
FakeIOSDevice
device
=
FakeIOSDevice
(
final
FakeIOSDevice
device
=
FakeIOSDevice
(
logReader:
fakeLogReader
,
logReader:
fakeLogReader
,
portForwarder:
portForwarder
,
portForwarder:
portForwarder
,
majorSdkVersion:
12
,
onGetLogReader:
()
{
onGetLogReader:
()
{
fakeLogReader
.
addLine
(
'Foo'
);
fakeLogReader
.
addLine
(
'Foo'
);
fakeLogReader
.
addLine
(
'The Dart VM service is listening on http://127.0.0.1:
$devicePort
'
);
fakeLogReader
.
addLine
(
'The Dart VM service is listening on http://127.0.0.1:
$devicePort
'
);
return
fakeLogReader
;
return
fakeLogReader
;
},
},
);
);
testDeviceManager
.
devices
=
<
Device
>[
device
];
testDeviceManager
.
devices
=
<
Device
>[
device
];
final
Completer
<
void
>
completer
=
Completer
<
void
>();
final
Completer
<
void
>
completer
=
Completer
<
void
>();
final
StreamSubscription
<
String
>
loggerSubscription
=
logger
.
stream
.
listen
((
String
message
)
{
final
StreamSubscription
<
String
>
loggerSubscription
=
logger
.
stream
.
listen
((
String
message
)
{
...
@@ -123,20 +121,7 @@ void main() {
...
@@ -123,20 +121,7 @@ void main() {
completer
.
complete
();
completer
.
complete
();
}
}
});
});
final
FakeHotRunner
hotRunner
=
FakeHotRunner
();
final
Future
<
void
>
task
=
createTestCommandRunner
(
AttachCommand
(
hotRunner
.
onAttach
=
(
Completer
<
DebugConnectionInfo
>?
connectionInfoCompleter
,
Completer
<
void
>?
appStartedCompleter
,
bool
allowExistingDdsInstance
,
bool
enableDevTools
,
)
async
=>
0
;
hotRunner
.
exited
=
false
;
hotRunner
.
isWaitingForObservatory
=
false
;
final
FakeHotRunnerFactory
hotRunnerFactory
=
FakeHotRunnerFactory
()
..
hotRunner
=
hotRunner
;
await
createTestCommandRunner
(
AttachCommand
(
hotRunnerFactory:
hotRunnerFactory
,
artifacts:
artifacts
,
artifacts:
artifacts
,
stdio:
stdio
,
stdio:
stdio
,
logger:
logger
,
logger:
logger
,
...
@@ -152,309 +137,15 @@ void main() {
...
@@ -152,309 +137,15 @@ void main() {
expect
(
portForwarder
.
hostPort
,
hostPort
);
expect
(
portForwarder
.
hostPort
,
hostPort
);
await
fakeLogReader
.
dispose
();
await
fakeLogReader
.
dispose
();
await
expectLoggerInterruptEndsTask
(
task
,
logger
);
await
loggerSubscription
.
cancel
();
await
loggerSubscription
.
cancel
();
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
Logger:
()
=>
logger
,
Logger:
()
=>
logger
,
DeviceManager:
()
=>
testDeviceManager
,
DeviceManager:
()
=>
testDeviceManager
,
MDnsVmServiceDiscovery:
()
=>
MDnsVmServiceDiscovery
(
MDnsObservatoryDiscovery:
()
=>
MDnsObservatoryDiscovery
(
mdnsClient:
FakeMDnsClient
(<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{}),
preliminaryMDnsClient:
FakeMDnsClient
(<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{}),
logger:
logger
,
flutterUsage:
TestUsage
(),
),
});
testUsingContext
(
'succeeds with iOS device with mDNS'
,
()
async
{
final
FakeIOSDevice
device
=
FakeIOSDevice
(
logReader:
fakeLogReader
,
portForwarder:
portForwarder
,
majorSdkVersion:
16
,
onGetLogReader:
()
{
fakeLogReader
.
addLine
(
'Foo'
);
fakeLogReader
.
addLine
(
'The Dart VM service is listening on http://127.0.0.1:
$devicePort
'
);
return
fakeLogReader
;
},
);
testDeviceManager
.
devices
=
<
Device
>[
device
];
final
FakeHotRunner
hotRunner
=
FakeHotRunner
();
hotRunner
.
onAttach
=
(
Completer
<
DebugConnectionInfo
>?
connectionInfoCompleter
,
Completer
<
void
>?
appStartedCompleter
,
bool
allowExistingDdsInstance
,
bool
enableDevTools
,
)
async
=>
0
;
hotRunner
.
exited
=
false
;
hotRunner
.
isWaitingForObservatory
=
false
;
final
FakeHotRunnerFactory
hotRunnerFactory
=
FakeHotRunnerFactory
()
..
hotRunner
=
hotRunner
;
await
createTestCommandRunner
(
AttachCommand
(
hotRunnerFactory:
hotRunnerFactory
,
artifacts:
artifacts
,
stdio:
stdio
,
logger:
logger
,
terminal:
terminal
,
signals:
signals
,
platform:
platform
,
processInfo:
processInfo
,
fileSystem:
testFileSystem
,
)).
run
(<
String
>[
'attach'
]);
await
fakeLogReader
.
dispose
();
expect
(
portForwarder
.
devicePort
,
devicePort
);
expect
(
portForwarder
.
hostPort
,
hostPort
);
expect
(
hotRunnerFactory
.
devices
,
hasLength
(
1
));
final
FlutterDevice
flutterDevice
=
hotRunnerFactory
.
devices
.
first
;
final
Uri
?
observatoryUri
=
await
flutterDevice
.
observatoryUris
?.
first
;
expect
(
observatoryUri
.
toString
(),
'http://127.0.0.1:
$hostPort
/xyz/'
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
Logger:
()
=>
logger
,
DeviceManager:
()
=>
testDeviceManager
,
MDnsVmServiceDiscovery:
()
=>
MDnsVmServiceDiscovery
(
mdnsClient:
FakeMDnsClient
(<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{}),
mdnsClient:
FakeMDnsClient
(<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{}),
preliminaryMDnsClient:
FakeMDnsClient
(
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
future
,
domainName:
'bar'
),
],
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
future
,
port:
devicePort
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
},
txtResponse:
<
String
,
List
<
TxtResourceRecord
>>{
'bar'
:
<
TxtResourceRecord
>[
TxtResourceRecord
(
'bar'
,
future
,
text:
'authCode=xyz
\n
'
),
],
},
),
logger:
logger
,
flutterUsage:
TestUsage
(),
),
});
testUsingContext
(
'succeeds with iOS device with mDNS network device'
,
()
async
{
final
FakeIOSDevice
device
=
FakeIOSDevice
(
logReader:
fakeLogReader
,
portForwarder:
portForwarder
,
majorSdkVersion:
16
,
interfaceType:
IOSDeviceConnectionInterface
.
network
,
);
testDeviceManager
.
devices
=
<
Device
>[
device
];
final
FakeHotRunner
hotRunner
=
FakeHotRunner
();
hotRunner
.
onAttach
=
(
Completer
<
DebugConnectionInfo
>?
connectionInfoCompleter
,
Completer
<
void
>?
appStartedCompleter
,
bool
allowExistingDdsInstance
,
bool
enableDevTools
,
)
async
=>
0
;
hotRunner
.
exited
=
false
;
hotRunner
.
isWaitingForObservatory
=
false
;
final
FakeHotRunnerFactory
hotRunnerFactory
=
FakeHotRunnerFactory
()
..
hotRunner
=
hotRunner
;
await
createTestCommandRunner
(
AttachCommand
(
hotRunnerFactory:
hotRunnerFactory
,
artifacts:
artifacts
,
stdio:
stdio
,
logger:
logger
,
terminal:
terminal
,
signals:
signals
,
platform:
platform
,
processInfo:
processInfo
,
fileSystem:
testFileSystem
,
)).
run
(<
String
>[
'attach'
]);
await
fakeLogReader
.
dispose
();
expect
(
portForwarder
.
devicePort
,
null
);
expect
(
portForwarder
.
hostPort
,
hostPort
);
expect
(
hotRunnerFactory
.
devices
,
hasLength
(
1
));
final
FlutterDevice
flutterDevice
=
hotRunnerFactory
.
devices
.
first
;
final
Uri
?
observatoryUri
=
await
flutterDevice
.
observatoryUris
?.
first
;
expect
(
observatoryUri
.
toString
(),
'http://111.111.111.111:123/xyz/'
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
Logger:
()
=>
logger
,
DeviceManager:
()
=>
testDeviceManager
,
MDnsVmServiceDiscovery:
()
=>
MDnsVmServiceDiscovery
(
mdnsClient:
FakeMDnsClient
(<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{}),
preliminaryMDnsClient:
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'
),
],
},
ipResponse:
<
String
,
List
<
IPAddressResourceRecord
>>{
'target-foo'
:
<
IPAddressResourceRecord
>[
IPAddressResourceRecord
(
'target-foo'
,
0
,
address:
InternetAddress
.
tryParse
(
'111.111.111.111'
)!),
],
},
txtResponse:
<
String
,
List
<
TxtResourceRecord
>>{
'srv-foo'
:
<
TxtResourceRecord
>[
TxtResourceRecord
(
'srv-foo'
,
future
,
text:
'authCode=xyz
\n
'
),
],
},
),
logger:
logger
,
flutterUsage:
TestUsage
(),
),
});
testUsingContext
(
'succeeds with iOS device with mDNS network device with debug-port'
,
()
async
{
final
FakeIOSDevice
device
=
FakeIOSDevice
(
logReader:
fakeLogReader
,
portForwarder:
portForwarder
,
majorSdkVersion:
16
,
interfaceType:
IOSDeviceConnectionInterface
.
network
,
);
testDeviceManager
.
devices
=
<
Device
>[
device
];
final
FakeHotRunner
hotRunner
=
FakeHotRunner
();
hotRunner
.
onAttach
=
(
Completer
<
DebugConnectionInfo
>?
connectionInfoCompleter
,
Completer
<
void
>?
appStartedCompleter
,
bool
allowExistingDdsInstance
,
bool
enableDevTools
,
)
async
=>
0
;
hotRunner
.
exited
=
false
;
hotRunner
.
isWaitingForObservatory
=
false
;
final
FakeHotRunnerFactory
hotRunnerFactory
=
FakeHotRunnerFactory
()
..
hotRunner
=
hotRunner
;
await
createTestCommandRunner
(
AttachCommand
(
hotRunnerFactory:
hotRunnerFactory
,
artifacts:
artifacts
,
stdio:
stdio
,
logger:
logger
,
terminal:
terminal
,
signals:
signals
,
platform:
platform
,
processInfo:
processInfo
,
fileSystem:
testFileSystem
,
)).
run
(<
String
>[
'attach'
,
'--debug-port'
,
'123'
]);
await
fakeLogReader
.
dispose
();
expect
(
portForwarder
.
devicePort
,
null
);
expect
(
portForwarder
.
hostPort
,
hostPort
);
expect
(
hotRunnerFactory
.
devices
,
hasLength
(
1
));
final
FlutterDevice
flutterDevice
=
hotRunnerFactory
.
devices
.
first
;
final
Uri
?
observatoryUri
=
await
flutterDevice
.
observatoryUris
?.
first
;
expect
(
observatoryUri
.
toString
(),
'http://111.111.111.111:123/xyz/'
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
Logger:
()
=>
logger
,
DeviceManager:
()
=>
testDeviceManager
,
MDnsVmServiceDiscovery:
()
=>
MDnsVmServiceDiscovery
(
mdnsClient:
FakeMDnsClient
(<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{}),
preliminaryMDnsClient:
FakeMDnsClient
(
<
PtrResourceRecord
>[
PtrResourceRecord
(
'bar'
,
future
,
domainName:
'srv-bar'
),
PtrResourceRecord
(
'foo'
,
future
,
domainName:
'srv-foo'
),
],
<
String
,
List
<
SrvResourceRecord
>>{
'srv-bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'srv-bar'
,
future
,
port:
321
,
weight:
1
,
priority:
1
,
target:
'target-bar'
),
],
'srv-foo'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'srv-foo'
,
future
,
port:
123
,
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'
)!),
],
},
txtResponse:
<
String
,
List
<
TxtResourceRecord
>>{
'srv-foo'
:
<
TxtResourceRecord
>[
TxtResourceRecord
(
'srv-foo'
,
future
,
text:
'authCode=xyz
\n
'
),
],
},
),
logger:
logger
,
flutterUsage:
TestUsage
(),
),
});
testUsingContext
(
'succeeds with iOS device with mDNS network device with debug-url'
,
()
async
{
final
FakeIOSDevice
device
=
FakeIOSDevice
(
logReader:
fakeLogReader
,
portForwarder:
portForwarder
,
majorSdkVersion:
16
,
interfaceType:
IOSDeviceConnectionInterface
.
network
,
);
testDeviceManager
.
devices
=
<
Device
>[
device
];
final
FakeHotRunner
hotRunner
=
FakeHotRunner
();
hotRunner
.
onAttach
=
(
Completer
<
DebugConnectionInfo
>?
connectionInfoCompleter
,
Completer
<
void
>?
appStartedCompleter
,
bool
allowExistingDdsInstance
,
bool
enableDevTools
,
)
async
=>
0
;
hotRunner
.
exited
=
false
;
hotRunner
.
isWaitingForObservatory
=
false
;
final
FakeHotRunnerFactory
hotRunnerFactory
=
FakeHotRunnerFactory
()
..
hotRunner
=
hotRunner
;
await
createTestCommandRunner
(
AttachCommand
(
hotRunnerFactory:
hotRunnerFactory
,
artifacts:
artifacts
,
stdio:
stdio
,
logger:
logger
,
terminal:
terminal
,
signals:
signals
,
platform:
platform
,
processInfo:
processInfo
,
fileSystem:
testFileSystem
,
)).
run
(<
String
>[
'attach'
,
'--debug-url'
,
'https://0.0.0.0:123'
]);
await
fakeLogReader
.
dispose
();
expect
(
portForwarder
.
devicePort
,
null
);
expect
(
portForwarder
.
hostPort
,
hostPort
);
expect
(
hotRunnerFactory
.
devices
,
hasLength
(
1
));
final
FlutterDevice
flutterDevice
=
hotRunnerFactory
.
devices
.
first
;
final
Uri
?
observatoryUri
=
await
flutterDevice
.
observatoryUris
?.
first
;
expect
(
observatoryUri
.
toString
(),
'http://111.111.111.111:123/xyz/'
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
Logger:
()
=>
logger
,
DeviceManager:
()
=>
testDeviceManager
,
MDnsVmServiceDiscovery:
()
=>
MDnsVmServiceDiscovery
(
mdnsClient:
FakeMDnsClient
(<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{}),
preliminaryMDnsClient:
FakeMDnsClient
(
<
PtrResourceRecord
>[
PtrResourceRecord
(
'bar'
,
future
,
domainName:
'srv-bar'
),
PtrResourceRecord
(
'foo'
,
future
,
domainName:
'srv-foo'
),
],
<
String
,
List
<
SrvResourceRecord
>>{
'srv-bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'srv-bar'
,
future
,
port:
321
,
weight:
1
,
priority:
1
,
target:
'target-bar'
),
],
'srv-foo'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'srv-foo'
,
future
,
port:
123
,
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'
)!),
],
},
txtResponse:
<
String
,
List
<
TxtResourceRecord
>>{
'srv-foo'
:
<
TxtResourceRecord
>[
TxtResourceRecord
(
'srv-foo'
,
future
,
text:
'authCode=xyz
\n
'
),
],
},
),
logger:
logger
,
logger:
logger
,
flutterUsage:
TestUsage
(),
flutterUsage:
TestUsage
(),
),
),
...
@@ -1288,16 +979,9 @@ class FakeIOSDevice extends Fake implements IOSDevice {
...
@@ -1288,16 +979,9 @@ class FakeIOSDevice extends Fake implements IOSDevice {
DevicePortForwarder
?
portForwarder
,
DevicePortForwarder
?
portForwarder
,
DeviceLogReader
?
logReader
,
DeviceLogReader
?
logReader
,
this
.
onGetLogReader
,
this
.
onGetLogReader
,
this
.
interfaceType
=
IOSDeviceConnectionInterface
.
none
,
this
.
majorSdkVersion
=
0
,
})
:
_portForwarder
=
portForwarder
,
_logReader
=
logReader
;
})
:
_portForwarder
=
portForwarder
,
_logReader
=
logReader
;
final
DevicePortForwarder
?
_portForwarder
;
final
DevicePortForwarder
?
_portForwarder
;
@override
int
majorSdkVersion
;
@override
final
IOSDeviceConnectionInterface
interfaceType
;
@override
@override
DevicePortForwarder
get
portForwarder
=>
_portForwarder
!;
DevicePortForwarder
get
portForwarder
=>
_portForwarder
!;
...
@@ -1345,14 +1029,12 @@ class FakeIOSDevice extends Fake implements IOSDevice {
...
@@ -1345,14 +1029,12 @@ class FakeIOSDevice extends Fake implements IOSDevice {
class
FakeMDnsClient
extends
Fake
implements
MDnsClient
{
class
FakeMDnsClient
extends
Fake
implements
MDnsClient
{
FakeMDnsClient
(
this
.
ptrRecords
,
this
.
srvResponse
,
{
FakeMDnsClient
(
this
.
ptrRecords
,
this
.
srvResponse
,
{
this
.
txtResponse
=
const
<
String
,
List
<
TxtResourceRecord
>>{},
this
.
txtResponse
=
const
<
String
,
List
<
TxtResourceRecord
>>{},
this
.
ipResponse
=
const
<
String
,
List
<
IPAddressResourceRecord
>>{},
this
.
osErrorOnStart
=
false
,
this
.
osErrorOnStart
=
false
,
});
});
final
List
<
PtrResourceRecord
>
ptrRecords
;
final
List
<
PtrResourceRecord
>
ptrRecords
;
final
Map
<
String
,
List
<
SrvResourceRecord
>>
srvResponse
;
final
Map
<
String
,
List
<
SrvResourceRecord
>>
srvResponse
;
final
Map
<
String
,
List
<
TxtResourceRecord
>>
txtResponse
;
final
Map
<
String
,
List
<
TxtResourceRecord
>>
txtResponse
;
final
Map
<
String
,
List
<
IPAddressResourceRecord
>>
ipResponse
;
final
bool
osErrorOnStart
;
final
bool
osErrorOnStart
;
@override
@override
...
@@ -1372,7 +1054,7 @@ class FakeMDnsClient extends Fake implements MDnsClient {
...
@@ -1372,7 +1054,7 @@ class FakeMDnsClient extends Fake implements MDnsClient {
ResourceRecordQuery
query
,
{
ResourceRecordQuery
query
,
{
Duration
timeout
=
const
Duration
(
seconds:
5
),
Duration
timeout
=
const
Duration
(
seconds:
5
),
})
{
})
{
if
(
T
==
PtrResourceRecord
&&
query
.
fullyQualifiedName
==
MDns
VmServiceDiscovery
.
dartVmService
Name
)
{
if
(
T
==
PtrResourceRecord
&&
query
.
fullyQualifiedName
==
MDns
ObservatoryDiscovery
.
dartObservatory
Name
)
{
return
Stream
<
PtrResourceRecord
>.
fromIterable
(
ptrRecords
)
as
Stream
<
T
>;
return
Stream
<
PtrResourceRecord
>.
fromIterable
(
ptrRecords
)
as
Stream
<
T
>;
}
}
if
(
T
==
SrvResourceRecord
)
{
if
(
T
==
SrvResourceRecord
)
{
...
@@ -1383,10 +1065,6 @@ class FakeMDnsClient extends Fake implements MDnsClient {
...
@@ -1383,10 +1065,6 @@ class FakeMDnsClient extends Fake implements MDnsClient {
final
String
key
=
query
.
fullyQualifiedName
;
final
String
key
=
query
.
fullyQualifiedName
;
return
Stream
<
TxtResourceRecord
>.
fromIterable
(
txtResponse
[
key
]
??
<
TxtResourceRecord
>[])
as
Stream
<
T
>;
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
'
);
throw
UnsupportedError
(
'Unsupported query type
$T
'
);
}
}
...
...
packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart
View file @
cbf2e168
...
@@ -21,8 +21,6 @@ import 'package:flutter_tools/src/commands/drive.dart';
...
@@ -21,8 +21,6 @@ import 'package:flutter_tools/src/commands/drive.dart';
import
'package:flutter_tools/src/dart/pub.dart'
;
import
'package:flutter_tools/src/dart/pub.dart'
;
import
'package:flutter_tools/src/device.dart'
;
import
'package:flutter_tools/src/device.dart'
;
import
'package:flutter_tools/src/drive/drive_service.dart'
;
import
'package:flutter_tools/src/drive/drive_service.dart'
;
import
'package:flutter_tools/src/ios/devices.dart'
;
import
'package:flutter_tools/src/ios/iproxy.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:package_config/package_config.dart'
;
import
'package:package_config/package_config.dart'
;
import
'package:test/fake.dart'
;
import
'package:test/fake.dart'
;
...
@@ -408,94 +406,6 @@ void main() {
...
@@ -408,94 +406,6 @@ void main() {
FileSystem:
()
=>
MemoryFileSystem
.
test
(),
FileSystem:
()
=>
MemoryFileSystem
.
test
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
testUsingContext
(
'Port publication not disabled for network device'
,
()
async
{
final
DriveCommand
command
=
DriveCommand
(
fileSystem:
fileSystem
,
logger:
logger
,
platform:
platform
,
signals:
signals
,
);
fileSystem
.
file
(
'lib/main.dart'
).
createSync
(
recursive:
true
);
fileSystem
.
file
(
'test_driver/main_test.dart'
).
createSync
(
recursive:
true
);
fileSystem
.
file
(
'pubspec.yaml'
).
createSync
();
final
Device
networkDevice
=
FakeIosDevice
()
..
interfaceType
=
IOSDeviceConnectionInterface
.
network
;
fakeDeviceManager
.
devices
=
<
Device
>[
networkDevice
];
await
expectLater
(()
=>
createTestCommandRunner
(
command
).
run
(<
String
>[
'drive'
,
]),
throwsToolExit
());
final
DebuggingOptions
options
=
await
command
.
createDebuggingOptions
(
false
);
expect
(
options
.
disablePortPublication
,
false
);
},
overrides:
<
Type
,
Generator
>{
Cache:
()
=>
Cache
.
test
(
processManager:
FakeProcessManager
.
any
()),
FileSystem:
()
=>
MemoryFileSystem
.
test
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
DeviceManager:
()
=>
fakeDeviceManager
,
});
testUsingContext
(
'Port publication is disabled for wired device'
,
()
async
{
final
DriveCommand
command
=
DriveCommand
(
fileSystem:
fileSystem
,
logger:
logger
,
platform:
platform
,
signals:
signals
,
);
fileSystem
.
file
(
'lib/main.dart'
).
createSync
(
recursive:
true
);
fileSystem
.
file
(
'test_driver/main_test.dart'
).
createSync
(
recursive:
true
);
fileSystem
.
file
(
'pubspec.yaml'
).
createSync
();
await
expectLater
(()
=>
createTestCommandRunner
(
command
).
run
(<
String
>[
'drive'
,
]),
throwsToolExit
());
final
Device
usbDevice
=
FakeIosDevice
()
..
interfaceType
=
IOSDeviceConnectionInterface
.
usb
;
fakeDeviceManager
.
devices
=
<
Device
>[
usbDevice
];
final
DebuggingOptions
options
=
await
command
.
createDebuggingOptions
(
false
);
expect
(
options
.
disablePortPublication
,
true
);
},
overrides:
<
Type
,
Generator
>{
Cache:
()
=>
Cache
.
test
(
processManager:
FakeProcessManager
.
any
()),
FileSystem:
()
=>
MemoryFileSystem
.
test
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
DeviceManager:
()
=>
fakeDeviceManager
,
});
testUsingContext
(
'Port publication does not default to enabled for network device if flag manually added'
,
()
async
{
final
DriveCommand
command
=
DriveCommand
(
fileSystem:
fileSystem
,
logger:
logger
,
platform:
platform
,
signals:
signals
,
);
fileSystem
.
file
(
'lib/main.dart'
).
createSync
(
recursive:
true
);
fileSystem
.
file
(
'test_driver/main_test.dart'
).
createSync
(
recursive:
true
);
fileSystem
.
file
(
'pubspec.yaml'
).
createSync
();
final
Device
networkDevice
=
FakeIosDevice
()
..
interfaceType
=
IOSDeviceConnectionInterface
.
network
;
fakeDeviceManager
.
devices
=
<
Device
>[
networkDevice
];
await
expectLater
(()
=>
createTestCommandRunner
(
command
).
run
(<
String
>[
'drive'
,
'--no-publish-port'
]),
throwsToolExit
());
final
DebuggingOptions
options
=
await
command
.
createDebuggingOptions
(
false
);
expect
(
options
.
disablePortPublication
,
true
);
},
overrides:
<
Type
,
Generator
>{
Cache:
()
=>
Cache
.
test
(
processManager:
FakeProcessManager
.
any
()),
FileSystem:
()
=>
MemoryFileSystem
.
test
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
DeviceManager:
()
=>
fakeDeviceManager
,
});
}
}
// Unfortunately Device, despite not being immutable, has an `operator ==`.
// Unfortunately Device, despite not being immutable, has an `operator ==`.
...
@@ -667,14 +577,3 @@ class FakeProcessSignal extends Fake implements io.ProcessSignal {
...
@@ -667,14 +577,3 @@ class FakeProcessSignal extends Fake implements io.ProcessSignal {
@override
@override
Stream
<
io
.
ProcessSignal
>
watch
()
=>
controller
.
stream
;
Stream
<
io
.
ProcessSignal
>
watch
()
=>
controller
.
stream
;
}
}
// 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
{
@override
IOSDeviceConnectionInterface
interfaceType
=
IOSDeviceConnectionInterface
.
usb
;
@override
Future
<
TargetPlatform
>
get
targetPlatform
async
=>
TargetPlatform
.
ios
;
}
packages/flutter_tools/test/general.shard/device_test.dart
View file @
cbf2e168
...
@@ -11,7 +11,6 @@ import 'package:flutter_tools/src/base/utils.dart';
...
@@ -11,7 +11,6 @@ import 'package:flutter_tools/src/base/utils.dart';
import
'package:flutter_tools/src/build_info.dart'
;
import
'package:flutter_tools/src/build_info.dart'
;
import
'package:flutter_tools/src/convert.dart'
;
import
'package:flutter_tools/src/convert.dart'
;
import
'package:flutter_tools/src/device.dart'
;
import
'package:flutter_tools/src/device.dart'
;
import
'package:flutter_tools/src/ios/iproxy.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:test/fake.dart'
;
import
'package:test/fake.dart'
;
...
@@ -555,53 +554,6 @@ void main() {
...
@@ -555,53 +554,6 @@ void main() {
);
);
});
});
testWithoutContext
(
'Get launch arguments for physical device with iPv4 network connection'
,
()
{
final
DebuggingOptions
original
=
DebuggingOptions
.
enabled
(
BuildInfo
.
debug
,
);
final
List
<
String
>
launchArguments
=
original
.
getIOSLaunchArguments
(
EnvironmentType
.
physical
,
null
,
<
String
,
Object
?>{},
interfaceType:
IOSDeviceConnectionInterface
.
network
,
);
expect
(
launchArguments
.
join
(
' '
),
<
String
>[
'--enable-dart-profiling'
,
'--enable-checked-mode'
,
'--verify-entry-points'
,
'--observatory-host=0.0.0.0'
,
].
join
(
' '
),
);
});
testWithoutContext
(
'Get launch arguments for physical device with iPv6 network connection'
,
()
{
final
DebuggingOptions
original
=
DebuggingOptions
.
enabled
(
BuildInfo
.
debug
,
);
final
List
<
String
>
launchArguments
=
original
.
getIOSLaunchArguments
(
EnvironmentType
.
physical
,
null
,
<
String
,
Object
?>{},
ipv6:
true
,
interfaceType:
IOSDeviceConnectionInterface
.
network
,
);
expect
(
launchArguments
.
join
(
' '
),
<
String
>[
'--enable-dart-profiling'
,
'--enable-checked-mode'
,
'--verify-entry-points'
,
'--observatory-host=::0'
,
].
join
(
' '
),
);
});
testWithoutContext
(
'Get launch arguments for physical device with debugging disabled with available launch arguments'
,
()
{
testWithoutContext
(
'Get launch arguments for physical device with debugging disabled with available launch arguments'
,
()
{
final
DebuggingOptions
original
=
DebuggingOptions
.
disabled
(
final
DebuggingOptions
original
=
DebuggingOptions
.
disabled
(
BuildInfo
.
debug
,
BuildInfo
.
debug
,
...
...
packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart
View file @
cbf2e168
...
@@ -19,11 +19,9 @@ import 'package:flutter_tools/src/ios/devices.dart';
...
@@ -19,11 +19,9 @@ import 'package:flutter_tools/src/ios/devices.dart';
import
'package:flutter_tools/src/ios/ios_deploy.dart'
;
import
'package:flutter_tools/src/ios/ios_deploy.dart'
;
import
'package:flutter_tools/src/ios/iproxy.dart'
;
import
'package:flutter_tools/src/ios/iproxy.dart'
;
import
'package:flutter_tools/src/ios/mac.dart'
;
import
'package:flutter_tools/src/ios/mac.dart'
;
import
'package:flutter_tools/src/mdns_discovery.dart'
;
import
'package:test/fake.dart'
;
import
'package:test/fake.dart'
;
import
'../../src/common.dart'
;
import
'../../src/common.dart'
;
import
'../../src/context.dart'
;
import
'../../src/fake_devices.dart'
;
import
'../../src/fake_devices.dart'
;
import
'../../src/fake_process_manager.dart'
;
import
'../../src/fake_process_manager.dart'
;
import
'../../src/fakes.dart'
;
import
'../../src/fakes.dart'
;
...
@@ -68,10 +66,9 @@ const FakeCommand kLaunchDebugCommand = FakeCommand(command: <String>[
...
@@ -68,10 +66,9 @@ const FakeCommand kLaunchDebugCommand = FakeCommand(command: <String>[
FakeCommand
attachDebuggerCommand
(
{
FakeCommand
attachDebuggerCommand
(
{
IOSink
?
stdin
,
IOSink
?
stdin
,
Completer
<
void
>?
completer
,
Completer
<
void
>?
completer
,
bool
isNetworkDevice
=
false
,
})
{
})
{
return
FakeCommand
(
return
FakeCommand
(
command:
<
String
>[
command:
const
<
String
>[
'script'
,
'script'
,
'-t'
,
'-t'
,
'0'
,
'0'
,
...
@@ -82,11 +79,8 @@ FakeCommand attachDebuggerCommand({
...
@@ -82,11 +79,8 @@ FakeCommand attachDebuggerCommand({
'--bundle'
,
'--bundle'
,
'/'
,
'/'
,
'--debug'
,
'--debug'
,
if
(!
isNetworkDevice
)
'--no-wifi'
,
'--no-wifi'
,
'--args'
,
'--args'
,
if
(
isNetworkDevice
)
'--enable-dart-profiling --enable-checked-mode --verify-entry-points --observatory-host=0.0.0.0'
else
'--enable-dart-profiling --enable-checked-mode --verify-entry-points'
,
'--enable-dart-profiling --enable-checked-mode --verify-entry-points'
,
],
],
completer:
completer
,
completer:
completer
,
...
@@ -194,7 +188,7 @@ void main() {
...
@@ -194,7 +188,7 @@ void main() {
expect
(
await
device
.
stopApp
(
iosApp
),
false
);
expect
(
await
device
.
stopApp
(
iosApp
),
false
);
});
});
testWithoutContext
(
'IOSDevice.startApp prints warning message if discovery takes longer than configured timeout
for wired device
'
,
()
async
{
testWithoutContext
(
'IOSDevice.startApp prints warning message if discovery takes longer than configured timeout'
,
()
async
{
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
BufferLogger
logger
=
BufferLogger
.
test
();
final
BufferLogger
logger
=
BufferLogger
.
test
();
final
CompleterIOSink
stdin
=
CompleterIOSink
();
final
CompleterIOSink
stdin
=
CompleterIOSink
();
...
@@ -232,59 +226,12 @@ void main() {
...
@@ -232,59 +226,12 @@ void main() {
expect
(
launchResult
.
started
,
true
);
expect
(
launchResult
.
started
,
true
);
expect
(
launchResult
.
hasObservatory
,
true
);
expect
(
launchResult
.
hasObservatory
,
true
);
expect
(
await
device
.
stopApp
(
iosApp
),
false
);
expect
(
await
device
.
stopApp
(
iosApp
),
false
);
expect
(
logger
.
errorText
,
contains
(
'
The Dart VM Service was
not discovered after 30 seconds. This is taking much longer than expected...'
));
expect
(
logger
.
errorText
,
contains
(
'
iOS Observatory
not discovered after 30 seconds. This is taking much longer than expected...'
));
expect
(
utf8
.
decoder
.
convert
(
stdin
.
writes
.
first
),
contains
(
'process interrupt'
));
expect
(
utf8
.
decoder
.
convert
(
stdin
.
writes
.
first
),
contains
(
'process interrupt'
));
completer
.
complete
();
completer
.
complete
();
expect
(
processManager
,
hasNoRemainingExpectations
);
expect
(
processManager
,
hasNoRemainingExpectations
);
});
});
testUsingContext
(
'IOSDevice.startApp prints warning message if discovery takes longer than configured timeout for wireless device'
,
()
async
{
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
BufferLogger
logger
=
BufferLogger
.
test
();
final
CompleterIOSink
stdin
=
CompleterIOSink
();
final
Completer
<
void
>
completer
=
Completer
<
void
>();
final
FakeProcessManager
processManager
=
FakeProcessManager
.
list
(<
FakeCommand
>[
attachDebuggerCommand
(
stdin:
stdin
,
completer:
completer
,
isNetworkDevice:
true
),
]);
final
IOSDevice
device
=
setUpIOSDevice
(
processManager:
processManager
,
fileSystem:
fileSystem
,
logger:
logger
,
interfaceType:
IOSDeviceConnectionInterface
.
network
,
);
final
IOSApp
iosApp
=
PrebuiltIOSApp
(
projectBundleId:
'app'
,
bundleName:
'Runner'
,
uncompressedBundle:
fileSystem
.
currentDirectory
,
applicationPackage:
fileSystem
.
currentDirectory
,
);
final
FakeDeviceLogReader
deviceLogReader
=
FakeDeviceLogReader
();
device
.
portForwarder
=
const
NoOpDevicePortForwarder
();
device
.
setLogReader
(
iosApp
,
deviceLogReader
);
// Start writing messages to the log reader.
deviceLogReader
.
addLine
(
'Foo'
);
deviceLogReader
.
addLine
(
'The Dart VM service is listening on http://127.0.0.1:456'
);
final
LaunchResult
launchResult
=
await
device
.
startApp
(
iosApp
,
prebuiltApplication:
true
,
debuggingOptions:
DebuggingOptions
.
enabled
(
BuildInfo
.
debug
),
platformArgs:
<
String
,
dynamic
>{},
discoveryTimeout:
Duration
.
zero
,
);
expect
(
launchResult
.
started
,
true
);
expect
(
launchResult
.
hasObservatory
,
true
);
expect
(
await
device
.
stopApp
(
iosApp
),
false
);
expect
(
logger
.
errorText
,
contains
(
'The Dart VM Service was not discovered after 45 seconds. This is taking much longer than expected...'
));
expect
(
logger
.
errorText
,
contains
(
'Click "Allow" to the prompt asking if you would like to find and connect devices on your local network.'
));
completer
.
complete
();
expect
(
processManager
,
hasNoRemainingExpectations
);
},
overrides:
<
Type
,
Generator
>{
MDnsVmServiceDiscovery:
()
=>
FakeMDnsVmServiceDiscovery
(),
});
testWithoutContext
(
'IOSDevice.startApp succeeds in release mode'
,
()
async
{
testWithoutContext
(
'IOSDevice.startApp succeeds in release mode'
,
()
async
{
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
FakeProcessManager
processManager
=
FakeProcessManager
.
list
(<
FakeCommand
>[
final
FakeProcessManager
processManager
=
FakeProcessManager
.
list
(<
FakeCommand
>[
...
@@ -558,7 +505,6 @@ IOSDevice setUpIOSDevice({
...
@@ -558,7 +505,6 @@ IOSDevice setUpIOSDevice({
Logger
?
logger
,
Logger
?
logger
,
ProcessManager
?
processManager
,
ProcessManager
?
processManager
,
IOSDeploy
?
iosDeploy
,
IOSDeploy
?
iosDeploy
,
IOSDeviceConnectionInterface
interfaceType
=
IOSDeviceConnectionInterface
.
usb
,
})
{
})
{
final
Artifacts
artifacts
=
Artifacts
.
test
();
final
Artifacts
artifacts
=
Artifacts
.
test
();
final
FakePlatform
macPlatform
=
FakePlatform
(
final
FakePlatform
macPlatform
=
FakePlatform
(
...
@@ -596,7 +542,7 @@ IOSDevice setUpIOSDevice({
...
@@ -596,7 +542,7 @@ IOSDevice setUpIOSDevice({
cache:
cache
,
cache:
cache
,
),
),
cpuArchitecture:
DarwinArch
.
arm64
,
cpuArchitecture:
DarwinArch
.
arm64
,
interfaceType:
interfaceType
,
interfaceType:
IOSDeviceConnectionInterface
.
usb
,
);
);
}
}
...
@@ -608,18 +554,3 @@ class FakeDevicePortForwarder extends Fake implements DevicePortForwarder {
...
@@ -608,18 +554,3 @@ class FakeDevicePortForwarder extends Fake implements DevicePortForwarder {
disposed
=
true
;
disposed
=
true
;
}
}
}
}
class
FakeMDnsVmServiceDiscovery
extends
Fake
implements
MDnsVmServiceDiscovery
{
@override
Future
<
Uri
?>
getVMServiceUriForLaunch
(
String
applicationId
,
Device
device
,
{
bool
usesIpv6
=
false
,
int
?
hostVmservicePort
,
required
int
deviceVmservicePort
,
bool
isNetworkDevice
=
false
,
Duration
timeout
=
Duration
.
zero
,
})
async
{
return
Uri
.
tryParse
(
'http://0.0.0.0:1234'
);
}
}
packages/flutter_tools/test/general.shard/macos/xcode_test.dart
View file @
cbf2e168
...
@@ -479,7 +479,7 @@ void main() {
...
@@ -479,7 +479,7 @@ void main() {
stdout:
devicesOutput
,
stdout:
devicesOutput
,
));
));
final
List
<
IOSDevice
>
devices
=
await
xcdevice
.
getAvailableIOSDevices
();
final
List
<
IOSDevice
>
devices
=
await
xcdevice
.
getAvailableIOSDevices
();
expect
(
devices
,
hasLength
(
4
));
expect
(
devices
,
hasLength
(
3
));
expect
(
devices
[
0
].
id
,
'00008027-00192736010F802E'
);
expect
(
devices
[
0
].
id
,
'00008027-00192736010F802E'
);
expect
(
devices
[
0
].
name
,
'An iPhone (Space Gray)'
);
expect
(
devices
[
0
].
name
,
'An iPhone (Space Gray)'
);
expect
(
await
devices
[
0
].
sdkNameAndVersion
,
'iOS 13.3 17C54'
);
expect
(
await
devices
[
0
].
sdkNameAndVersion
,
'iOS 13.3 17C54'
);
...
@@ -488,14 +488,10 @@ void main() {
...
@@ -488,14 +488,10 @@ void main() {
expect
(
devices
[
1
].
name
,
'iPad 1'
);
expect
(
devices
[
1
].
name
,
'iPad 1'
);
expect
(
await
devices
[
1
].
sdkNameAndVersion
,
'iOS 10.1 14C54'
);
expect
(
await
devices
[
1
].
sdkNameAndVersion
,
'iOS 10.1 14C54'
);
expect
(
devices
[
1
].
cpuArchitecture
,
DarwinArch
.
armv7
);
expect
(
devices
[
1
].
cpuArchitecture
,
DarwinArch
.
armv7
);
expect
(
devices
[
2
].
id
,
'
234234234234234234345445687594e089dede3c4
4'
);
expect
(
devices
[
2
].
id
,
'
f577a7903cc54959be2e34bc4f7f80b7009efcf
4'
);
expect
(
devices
[
2
].
name
,
'
A networked iPad
'
);
expect
(
devices
[
2
].
name
,
'
iPad 2
'
);
expect
(
await
devices
[
2
].
sdkNameAndVersion
,
'iOS 10.1 14C54'
);
expect
(
await
devices
[
2
].
sdkNameAndVersion
,
'iOS 10.1 14C54'
);
expect
(
devices
[
2
].
cpuArchitecture
,
DarwinArch
.
arm64
);
// Defaults to arm64 for unknown architecture.
expect
(
devices
[
2
].
cpuArchitecture
,
DarwinArch
.
arm64
);
// Defaults to arm64 for unknown architecture.
expect
(
devices
[
3
].
id
,
'f577a7903cc54959be2e34bc4f7f80b7009efcf4'
);
expect
(
devices
[
3
].
name
,
'iPad 2'
);
expect
(
await
devices
[
3
].
sdkNameAndVersion
,
'iOS 10.1 14C54'
);
expect
(
devices
[
3
].
cpuArchitecture
,
DarwinArch
.
arm64
);
// Defaults to arm64 for unknown architecture.
expect
(
fakeProcessManager
,
hasNoRemainingExpectations
);
expect
(
fakeProcessManager
,
hasNoRemainingExpectations
);
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
Platform:
()
=>
macPlatform
,
Platform:
()
=>
macPlatform
,
...
...
packages/flutter_tools/test/general.shard/mdns_discovery_test.dart
View file @
cbf2e168
...
@@ -17,7 +17,7 @@ import '../src/common.dart';
...
@@ -17,7 +17,7 @@ import '../src/common.dart';
void
main
(
)
{
void
main
(
)
{
group
(
'mDNS Discovery'
,
()
{
group
(
'mDNS Discovery'
,
()
{
final
int
future
=
DateTime
.
now
().
add
(
const
Duration
(
days:
1
)
).
millisecondsSinceEpoch
;
final
int
year3000
=
DateTime
(
3000
).
millisecondsSinceEpoch
;
setUp
(()
{
setUp
(()
{
setNetworkInterfaceLister
(
setNetworkInterfaceLister
(
...
@@ -33,106 +33,28 @@ void main() {
...
@@ -33,106 +33,28 @@ void main() {
resetNetworkInterfaceLister
();
resetNetworkInterfaceLister
();
});
});
group
(
'for attach'
,
()
{
late
MDnsClient
emptyClient
;
setUp
(()
{
testWithoutContext
(
'No ports available'
,
()
async
{
emptyClient
=
FakeMDnsClient
(<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{});
final
MDnsClient
client
=
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
=
MDnsVmService
Discovery
(
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatory
Discovery
(
mdnsClient:
client
,
mdnsClient:
client
,
preliminaryMDnsClient:
emptyClient
,
logger:
BufferLogger
.
test
(),
logger:
BufferLogger
.
test
(),
flutterUsage:
TestUsage
(),
flutterUsage:
TestUsage
(),
);
);
final
int
?
port
=
(
await
portDiscovery
.
query
())?.
port
;
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
(
'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
);
expect
(
port
,
isNull
);
});
});
testWithoutContext
(
'Prints helpful message when there is no ipv4 link local address.'
,
()
async
{
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
BufferLogger
logger
=
BufferLogger
.
test
();
final
MDnsVmServiceDiscovery
portDiscovery
=
MDnsVmServiceDiscovery
(
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
emptyClient
,
mdnsClient:
client
,
preliminaryMDnsClient:
emptyClient
,
logger:
logger
,
logger:
logger
,
flutterUsage:
TestUsage
(),
flutterUsage:
TestUsage
(),
);
);
final
Uri
?
uri
=
await
portDiscovery
.
getVMServiceUriForAttach
(
final
Uri
?
uri
=
await
portDiscovery
.
getObservatoryUri
(
''
,
''
,
FakeIOSDevice
(),
FakeIOSDevice
(),
);
);
...
@@ -143,557 +65,190 @@ void main() {
...
@@ -143,557 +65,190 @@ void main() {
testWithoutContext
(
'One port available, no appId'
,
()
async
{
testWithoutContext
(
'One port available, no appId'
,
()
async
{
final
MDnsClient
client
=
FakeMDnsClient
(
final
MDnsClient
client
=
FakeMDnsClient
(
<
PtrResourceRecord
>[
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
future
,
domainName:
'bar'
),
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
],
],
<
String
,
List
<
SrvResourceRecord
>>{
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
future
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
],
},
},
);
);
final
MDnsVmServiceDiscovery
portDiscovery
=
MDnsVmService
Discovery
(
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatory
Discovery
(
mdnsClient:
client
,
mdnsClient:
client
,
preliminaryMDnsClient:
emptyClient
,
logger:
BufferLogger
.
test
(),
logger:
BufferLogger
.
test
(),
flutterUsage:
TestUsage
(),
flutterUsage:
TestUsage
(),
);
);
final
int
?
port
=
(
await
portDiscovery
.
queryForAttach
())?.
port
;
final
int
?
port
=
(
await
portDiscovery
.
query
())?.
port
;
expect
(
port
,
123
);
expect
(
port
,
123
);
});
});
testWithoutContext
(
'One port available, no appId, with authCode'
,
()
async
{
testWithoutContext
(
'One port available, no appId, with authCode'
,
()
async
{
final
MDnsClient
client
=
FakeMDnsClient
(
final
MDnsClient
client
=
FakeMDnsClient
(
<
PtrResourceRecord
>[
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
future
,
domainName:
'bar'
),
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
],
],
<
String
,
List
<
SrvResourceRecord
>>{
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
future
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
],
},
},
txtResponse:
<
String
,
List
<
TxtResourceRecord
>>{
txtResponse:
<
String
,
List
<
TxtResourceRecord
>>{
'bar'
:
<
TxtResourceRecord
>[
'bar'
:
<
TxtResourceRecord
>[
TxtResourceRecord
(
'bar'
,
future
,
text:
'authCode=xyz
\n
'
),
TxtResourceRecord
(
'bar'
,
year3000
,
text:
'authCode=xyz
\n
'
),
],
],
},
},
);
);
final
MDnsVmServiceDiscovery
portDiscovery
=
MDnsVmService
Discovery
(
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatory
Discovery
(
mdnsClient:
client
,
mdnsClient:
client
,
preliminaryMDnsClient:
emptyClient
,
logger:
BufferLogger
.
test
(),
logger:
BufferLogger
.
test
(),
flutterUsage:
TestUsage
(),
flutterUsage:
TestUsage
(),
);
);
final
MDnsVmServiceDiscoveryResult
?
result
=
await
portDiscovery
.
queryForAttach
();
final
MDnsObservatoryDiscoveryResult
?
result
=
await
portDiscovery
.
query
();
expect
(
result
?.
port
,
123
);
expect
(
result
?.
port
,
123
);
expect
(
result
?.
authCode
,
'xyz/'
);
expect
(
result
?.
authCode
,
'xyz/'
);
});
});
testWithoutContext
(
'Multiple ports available, with
appId'
,
()
async
{
testWithoutContext
(
'Multiple ports available, without
appId'
,
()
async
{
final
MDnsClient
client
=
FakeMDnsClient
(
final
MDnsClient
client
=
FakeMDnsClient
(
<
PtrResourceRecord
>[
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
future
,
domainName:
'bar'
),
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
PtrResourceRecord
(
'baz'
,
future
,
domainName:
'fiz'
),
PtrResourceRecord
(
'baz'
,
year3000
,
domainName:
'fiz'
),
],
],
<
String
,
List
<
SrvResourceRecord
>>{
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
future
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
],
'fiz'
:
<
SrvResourceRecord
>[
'fiz'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'fiz'
,
future
,
port:
321
,
weight:
1
,
priority:
1
,
target:
'local'
),
SrvResourceRecord
(
'fiz'
,
year3000
,
port:
321
,
weight:
1
,
priority:
1
,
target:
'local'
),
],
],
},
},
);
);
final
MDnsVmServiceDiscovery
portDiscovery
=
MDnsVmService
Discovery
(
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatory
Discovery
(
mdnsClient:
client
,
mdnsClient:
client
,
preliminaryMDnsClient:
emptyClient
,
logger:
BufferLogger
.
test
(),
logger:
BufferLogger
.
test
(),
flutterUsage:
TestUsage
(),
flutterUsage:
TestUsage
(),
);
);
final
int
?
port
=
(
await
portDiscovery
.
queryForAttach
(
applicationId:
'fiz'
))?.
port
;
expect
(
portDiscovery
.
query
,
throwsToolExit
());
expect
(
port
,
321
);
});
});
testWithoutContext
(
'Multiple ports available per process
, with appId'
,
()
async
{
testWithoutContext
(
'Multiple ports available
, with appId'
,
()
async
{
final
MDnsClient
client
=
FakeMDnsClient
(
final
MDnsClient
client
=
FakeMDnsClient
(
<
PtrResourceRecord
>[
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
future
,
domainName:
'bar'
),
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
PtrResourceRecord
(
'baz'
,
future
,
domainName:
'fiz'
),
PtrResourceRecord
(
'baz'
,
year3000
,
domainName:
'fiz'
),
],
],
<
String
,
List
<
SrvResourceRecord
>>{
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
future
,
port:
1234
,
weight:
1
,
priority:
1
,
target:
'appId'
),
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
SrvResourceRecord
(
'bar'
,
future
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
],
'fiz'
:
<
SrvResourceRecord
>[
'fiz'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'fiz'
,
future
,
port:
4321
,
weight:
1
,
priority:
1
,
target:
'local'
),
SrvResourceRecord
(
'fiz'
,
year3000
,
port:
321
,
weight:
1
,
priority:
1
,
target:
'local'
),
SrvResourceRecord
(
'fiz'
,
future
,
port:
321
,
weight:
1
,
priority:
1
,
target:
'local'
),
],
],
},
},
);
);
final
MDnsVmServiceDiscovery
portDiscovery
=
MDnsVmService
Discovery
(
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatory
Discovery
(
mdnsClient:
client
,
mdnsClient:
client
,
preliminaryMDnsClient:
emptyClient
,
logger:
BufferLogger
.
test
(),
logger:
BufferLogger
.
test
(),
flutterUsage:
TestUsage
(),
flutterUsage:
TestUsage
(),
);
);
final
int
?
port
=
(
await
portDiscovery
.
queryForAttach
(
applicationId:
'bar'
))?.
port
;
final
int
?
port
=
(
await
portDiscovery
.
query
(
applicationId:
'fiz'
))?.
port
;
expect
(
port
,
1234
);
expect
(
port
,
321
);
});
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 network 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
,
isNetworkDevice:
true
,
);
expect
(
uri
.
toString
(),
'http://111.111.111.111:1234/xyz/'
);
});
});
testWithoutContext
(
'Get network device IP (iPv6)
'
,
()
async
{
testWithoutContext
(
'Multiple ports available per process, with appId
'
,
()
async
{
final
MDnsClient
client
=
FakeMDnsClient
(
final
MDnsClient
client
=
FakeMDnsClient
(
<
PtrResourceRecord
>[
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
future
,
domainName:
'bar'
),
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
PtrResourceRecord
(
'baz'
,
year3000
,
domainName:
'fiz'
),
],
],
<
String
,
List
<
SrvResourceRecord
>>{
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
future
,
port:
1234
,
weight:
1
,
priority:
1
,
target:
'appId'
),
SrvResourceRecord
(
'bar'
,
year3000
,
port:
1234
,
weight:
1
,
priority:
1
,
target:
'appId'
),
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
],
},
'fiz'
:
<
SrvResourceRecord
>[
ipResponse:
<
String
,
List
<
IPAddressResourceRecord
>>{
SrvResourceRecord
(
'fiz'
,
year3000
,
port:
4321
,
weight:
1
,
priority:
1
,
target:
'local'
),
'appId'
:
<
IPAddressResourceRecord
>[
SrvResourceRecord
(
'fiz'
,
year3000
,
port:
321
,
weight:
1
,
priority:
1
,
target:
'local'
),
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
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
final
MDnsVmServiceDiscovery
portDiscovery
=
MDnsVmServiceDiscovery
(
mdnsClient:
client
,
mdnsClient:
client
,
preliminaryMDnsClient:
emptyClient
,
logger:
BufferLogger
.
test
(),
logger:
BufferLogger
.
test
(),
flutterUsage:
TestUsage
(),
flutterUsage:
TestUsage
(),
);
);
final
Uri
?
uri
=
await
portDiscovery
.
getVMServiceUriForAttach
(
final
int
?
port
=
(
await
portDiscovery
.
query
(
applicationId:
'bar'
))?.
port
;
'bar'
,
expect
(
port
,
1234
);
device
,
isNetworkDevice:
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
{
testWithoutContext
(
'Query returns null
'
,
()
async
{
final
MDnsClient
client
=
FakeMDnsClient
(
final
MDnsClient
client
=
FakeMDnsClient
(
<
PtrResourceRecord
>[
<
PtrResourceRecord
>[],
PtrResourceRecord
(
'foo'
,
future
,
domainName:
'srv-foo'
),
<
String
,
List
<
SrvResourceRecord
>>{},
],
<
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
(
'No ports available'
,
()
async
{
final
MDnsClient
client
=
FakeMDnsClient
(<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{});
final
MDnsVmServiceDiscovery
portDiscovery
=
MDnsVmService
Discovery
(
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatory
Discovery
(
mdnsClient:
client
,
mdnsClient:
client
,
logger:
BufferLogger
.
test
(),
logger:
BufferLogger
.
test
(),
flutterUsage:
TestUsage
(),
flutterUsage:
TestUsage
(),
);
);
final
int
?
port
=
(
await
portDiscovery
.
query
(
applicationId:
'bar'
))?.
port
;
final
MDnsVmServiceDiscoveryResult
?
result
=
await
portDiscovery
.
queryForLaunch
(
expect
(
port
,
isNull
);
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
{
testWithoutContext
(
'Throws Exception when client throws OSError on start'
,
()
async
{
final
MDnsClient
client
=
FakeMDnsClient
(
final
MDnsClient
client
=
FakeMDnsClient
(<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{},
osErrorOnStart:
true
);
<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{},
osErrorOnStart:
true
,
);
final
MDnsVmServiceDiscovery
portDiscovery
=
MDnsVmServiceDiscovery
(
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
client
,
mdnsClient:
client
,
logger:
BufferLogger
.
test
(),
logger:
BufferLogger
.
test
(),
flutterUsage:
TestUsage
(),
flutterUsage:
TestUsage
(),
);
);
expect
(
expect
(
()
async
=>
portDiscovery
.
queryForLaunch
(
applicationId:
'app-id'
,
deviceVmservicePort:
123
),
()
async
=>
portDiscovery
.
query
(
),
throwsException
,
throwsException
,
);
);
});
});
testWithoutContext
(
'Correctly builds VM Service
URI with hostVmservicePort == 0'
,
()
async
{
testWithoutContext
(
'Correctly builds Observatory
URI with hostVmservicePort == 0'
,
()
async
{
final
MDnsClient
client
=
FakeMDnsClient
(
final
MDnsClient
client
=
FakeMDnsClient
(
<
PtrResourceRecord
>[
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
future
,
domainName:
'bar'
),
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
],
],
<
String
,
List
<
SrvResourceRecord
>>{
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
future
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
],
},
},
);
);
final
FakeIOSDevice
device
=
FakeIOSDevice
();
final
FakeIOSDevice
device
=
FakeIOSDevice
();
final
MDnsVmServiceDiscovery
portDiscovery
=
MDnsVmService
Discovery
(
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatory
Discovery
(
mdnsClient:
client
,
mdnsClient:
client
,
logger:
BufferLogger
.
test
(),
logger:
BufferLogger
.
test
(),
flutterUsage:
TestUsage
(),
flutterUsage:
TestUsage
(),
);
);
final
Uri
?
uri
=
await
portDiscovery
.
getVMServiceUriForLaunch
(
final
Uri
?
uri
=
await
portDiscovery
.
getObservatoryUri
(
'bar'
,
device
,
hostVmservicePort:
0
);
'bar'
,
device
,
hostVmservicePort:
0
,
deviceVmservicePort:
123
,
);
expect
(
uri
.
toString
(),
'http://127.0.0.1:123/'
);
expect
(
uri
.
toString
(),
'http://127.0.0.1:123/'
);
});
});
testWithoutContext
(
'Get network 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
,
isNetworkDevice:
true
,
deviceVmservicePort:
1234
,
);
expect
(
uri
.
toString
(),
'http://111.111.111.111:1234/xyz/'
);
});
testWithoutContext
(
'Get network 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
,
isNetworkDevice:
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
(
'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
);
});
});
});
}
}
class
FakeMDnsClient
extends
Fake
implements
MDnsClient
{
class
FakeMDnsClient
extends
Fake
implements
MDnsClient
{
FakeMDnsClient
(
this
.
ptrRecords
,
this
.
srvResponse
,
{
FakeMDnsClient
(
this
.
ptrRecords
,
this
.
srvResponse
,
{
this
.
txtResponse
=
const
<
String
,
List
<
TxtResourceRecord
>>{},
this
.
txtResponse
=
const
<
String
,
List
<
TxtResourceRecord
>>{},
this
.
ipResponse
=
const
<
String
,
List
<
IPAddressResourceRecord
>>{},
this
.
osErrorOnStart
=
false
,
this
.
osErrorOnStart
=
false
,
});
});
final
List
<
PtrResourceRecord
>
ptrRecords
;
final
List
<
PtrResourceRecord
>
ptrRecords
;
final
Map
<
String
,
List
<
SrvResourceRecord
>>
srvResponse
;
final
Map
<
String
,
List
<
SrvResourceRecord
>>
srvResponse
;
final
Map
<
String
,
List
<
TxtResourceRecord
>>
txtResponse
;
final
Map
<
String
,
List
<
TxtResourceRecord
>>
txtResponse
;
final
Map
<
String
,
List
<
IPAddressResourceRecord
>>
ipResponse
;
final
bool
osErrorOnStart
;
final
bool
osErrorOnStart
;
@override
@override
...
@@ -713,7 +268,7 @@ class FakeMDnsClient extends Fake implements MDnsClient {
...
@@ -713,7 +268,7 @@ class FakeMDnsClient extends Fake implements MDnsClient {
ResourceRecordQuery
query
,
{
ResourceRecordQuery
query
,
{
Duration
timeout
=
const
Duration
(
seconds:
5
),
Duration
timeout
=
const
Duration
(
seconds:
5
),
})
{
})
{
if
(
T
==
PtrResourceRecord
&&
query
.
fullyQualifiedName
==
MDns
VmServiceDiscovery
.
dartVmService
Name
)
{
if
(
T
==
PtrResourceRecord
&&
query
.
fullyQualifiedName
==
MDns
ObservatoryDiscovery
.
dartObservatory
Name
)
{
return
Stream
<
PtrResourceRecord
>.
fromIterable
(
ptrRecords
)
as
Stream
<
T
>;
return
Stream
<
PtrResourceRecord
>.
fromIterable
(
ptrRecords
)
as
Stream
<
T
>;
}
}
if
(
T
==
SrvResourceRecord
)
{
if
(
T
==
SrvResourceRecord
)
{
...
@@ -724,10 +279,6 @@ class FakeMDnsClient extends Fake implements MDnsClient {
...
@@ -724,10 +279,6 @@ class FakeMDnsClient extends Fake implements MDnsClient {
final
String
key
=
query
.
fullyQualifiedName
;
final
String
key
=
query
.
fullyQualifiedName
;
return
Stream
<
TxtResourceRecord
>.
fromIterable
(
txtResponse
[
key
]
??
<
TxtResourceRecord
>[])
as
Stream
<
T
>;
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
'
);
throw
UnsupportedError
(
'Unsupported query type
$T
'
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment