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
0b24a5a2
Unverified
Commit
0b24a5a2
authored
Sep 18, 2019
by
Christopher Fujino
Committed by
GitHub
Sep 18, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement mdns for `flutter run` (#40447)
parent
431b82fd
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
408 additions
and
298 deletions
+408
-298
attach.dart
packages/flutter_tools/lib/src/commands/attach.dart
+14
-154
context_runner.dart
packages/flutter_tools/lib/src/context_runner.dart
+2
-0
devices.dart
packages/flutter_tools/lib/src/ios/devices.dart
+24
-4
mdns_discovery.dart
packages/flutter_tools/lib/src/mdns_discovery.dart
+174
-0
attach_test.dart
...lutter_tools/test/general.shard/commands/attach_test.dart
+6
-129
devices_test.dart
...es/flutter_tools/test/general.shard/ios/devices_test.dart
+50
-11
mdns_discovery_test.dart
...flutter_tools/test/general.shard/mdns_discovery_test.dart
+138
-0
No files found.
packages/flutter_tools/lib/src/commands/attach.dart
View file @
0b24a5a2
...
...
@@ -4,8 +4,6 @@
import
'dart:async'
;
import
'package:multicast_dns/multicast_dns.dart'
;
import
'../artifacts.dart'
;
import
'../base/common.dart'
;
import
'../base/context.dart'
;
...
...
@@ -21,6 +19,7 @@ import '../fuchsia/fuchsia_device.dart';
import
'../globals.dart'
;
import
'../ios/devices.dart'
;
import
'../ios/simulators.dart'
;
import
'../mdns_discovery.dart'
;
import
'../project.dart'
;
import
'../protocol_discovery.dart'
;
import
'../resident_runner.dart'
;
...
...
@@ -207,7 +206,7 @@ class AttachCommand extends FlutterCommand {
final
String
hostname
=
usesIpv6
?
ipv6Loopback
:
ipv4Loopback
;
bool
attachLogger
=
false
;
if
(
devicePort
==
null
&&
debugUri
==
null
)
{
if
(
devicePort
==
null
&&
debugUri
==
null
)
{
if
(
device
is
FuchsiaDevice
)
{
attachLogger
=
true
;
final
String
module
=
argResults
[
'module'
];
...
...
@@ -229,10 +228,11 @@ class AttachCommand extends FlutterCommand {
rethrow
;
}
}
else
if
((
device
is
IOSDevice
)
||
(
device
is
IOSSimulator
))
{
final
MDnsObservatoryDiscoveryResult
result
=
await
MDnsObservatoryDiscovery
().
query
(
applicationId:
appId
);
if
(
result
!=
null
)
{
observatoryUri
=
await
_buildObservatoryUri
(
device
,
hostname
,
result
.
port
,
result
.
authCode
);
}
observatoryUri
=
await
MDnsObservatoryDiscovery
.
instance
.
getObservatoryUri
(
appId
,
device
,
usesIpv6
,
);
}
// If MDNS discovery fails or we're not on iOS, fallback to ProtocolDiscovery.
if
(
observatoryUri
==
null
)
{
...
...
@@ -254,8 +254,13 @@ class AttachCommand extends FlutterCommand {
}
}
}
else
{
observatoryUri
=
await
_buildObservatoryUri
(
device
,
debugUri
?.
host
??
hostname
,
devicePort
??
debugUri
.
port
,
debugUri
?.
path
);
observatoryUri
=
await
buildObservatoryUri
(
device
,
debugUri
?.
host
??
hostname
,
devicePort
??
debugUri
.
port
,
observatoryPort
,
debugUri
?.
path
,
);
}
try
{
final
bool
useHot
=
getBuildInfo
().
isDebug
;
...
...
@@ -337,22 +342,6 @@ class AttachCommand extends FlutterCommand {
}
Future
<
void
>
_validateArguments
()
async
{
}
Future
<
Uri
>
_buildObservatoryUri
(
Device
device
,
String
host
,
int
devicePort
,
[
String
authCode
])
async
{
String
path
=
'/'
;
if
(
authCode
!=
null
)
{
path
=
authCode
;
}
// Not having a trailing slash can cause problems in some situations.
// Ensure that there's one present.
if
(!
path
.
endsWith
(
'/'
))
{
path
+=
'/'
;
}
final
int
localPort
=
observatoryPort
??
await
device
.
portForwarder
.
forward
(
devicePort
);
return
Uri
(
scheme:
'http'
,
host:
host
,
port:
localPort
,
path:
path
);
}
}
class
HotRunnerFactory
{
...
...
@@ -383,132 +372,3 @@ class HotRunnerFactory {
ipv6:
ipv6
,
);
}
class
MDnsObservatoryDiscoveryResult
{
MDnsObservatoryDiscoveryResult
(
this
.
port
,
this
.
authCode
);
final
int
port
;
final
String
authCode
;
}
/// A wrapper around [MDnsClient] to find a Dart observatory instance.
class
MDnsObservatoryDiscovery
{
/// Creates a new [MDnsObservatoryDiscovery] object.
///
/// The [client] parameter will be defaulted to a new [MDnsClient] if null.
/// 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
})
:
client
=
mdnsClient
??
MDnsClient
();
/// The [MDnsClient] used to do a lookup.
final
MDnsClient
client
;
static
const
String
dartObservatoryName
=
'_dartobservatory._tcp.local'
;
/// Executes an mDNS query for a Dart Observatory.
///
/// 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
/// the bundle ID.
///
/// If it is not null, this method will find the port and authentication code
/// of the Dart Observatory for that application. If it cannot find a Dart
/// Observatory matching that application identifier, it will call
/// [throwToolExit].
///
/// If it is null and there are multiple ports available, the user will be
/// prompted with a list of available observatory ports and asked to select
/// one.
///
/// If it is null and there is only one available instance of Observatory,
/// it will return that instance's information regardless of what application
/// the Observatory instance is for.
Future
<
MDnsObservatoryDiscoveryResult
>
query
({
String
applicationId
})
async
{
printStatus
(
'Checking for advertised Dart observatories...'
);
try
{
await
client
.
start
();
final
List
<
PtrResourceRecord
>
pointerRecords
=
await
client
.
lookup
<
PtrResourceRecord
>(
ResourceRecordQuery
.
serverPointer
(
dartObservatoryName
),
)
.
toList
();
if
(
pointerRecords
.
isEmpty
)
{
return
null
;
}
// We have no guarantee that we won't get multiple hits from the same
// service on this.
final
List
<
String
>
uniqueDomainNames
=
pointerRecords
.
map
<
String
>((
PtrResourceRecord
record
)
=>
record
.
domainName
)
.
toSet
()
.
toList
();
String
domainName
;
if
(
applicationId
!=
null
)
{
for
(
String
name
in
uniqueDomainNames
)
{
if
(
name
.
toLowerCase
().
startsWith
(
applicationId
.
toLowerCase
()))
{
domainName
=
name
;
break
;
}
}
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
{
domainName
=
pointerRecords
[
0
].
domainName
;
}
printStatus
(
'Checking for available port on
$domainName
'
);
// Here, if we get more than one, it should just be a duplicate.
final
List
<
SrvResourceRecord
>
srv
=
await
client
.
lookup
<
SrvResourceRecord
>(
ResourceRecordQuery
.
service
(
domainName
),
)
.
toList
();
if
(
srv
.
isEmpty
)
{
return
null
;
}
if
(
srv
.
length
>
1
)
{
printError
(
'Unexpectedly found more than one observatory report for
$domainName
'
'- using first one (
${srv.first.port}
).'
);
}
printStatus
(
'Checking for authentication code for
$domainName
'
);
final
List
<
TxtResourceRecord
>
txt
=
await
client
.
lookup
<
TxtResourceRecord
>(
ResourceRecordQuery
.
text
(
domainName
),
)
?.
toList
();
if
(
txt
==
null
||
txt
.
isEmpty
)
{
return
MDnsObservatoryDiscoveryResult
(
srv
.
first
.
port
,
''
);
}
String
authCode
=
''
;
const
String
authCodePrefix
=
'authCode='
;
String
raw
=
txt
.
first
.
text
;
// TXT has a format of [<length byte>, text], so if the length is 2,
// that means that TXT is empty.
if
(
raw
.
length
>
2
)
{
// Remove length byte from raw txt.
raw
=
raw
.
substring
(
1
);
if
(
raw
.
startsWith
(
authCodePrefix
))
{
authCode
=
raw
.
substring
(
authCodePrefix
.
length
);
// The Observatory currently expects a trailing '/' as part of the
// URI, otherwise an invalid authentication code response is given.
if
(!
authCode
.
endsWith
(
'/'
))
{
authCode
+=
'/'
;
}
}
}
return
MDnsObservatoryDiscoveryResult
(
srv
.
first
.
port
,
authCode
);
}
finally
{
client
.
stop
();
}
}
}
packages/flutter_tools/lib/src/context_runner.dart
View file @
0b24a5a2
...
...
@@ -45,6 +45,7 @@ import 'macos/cocoapods_validator.dart';
import
'macos/macos_workflow.dart'
;
import
'macos/xcode.dart'
;
import
'macos/xcode_validator.dart'
;
import
'mdns_discovery.dart'
;
import
'reporting/reporting.dart'
;
import
'run_hot.dart'
;
import
'version.dart'
;
...
...
@@ -101,6 +102,7 @@ Future<T> runInContext<T>(
LinuxWorkflow:
()
=>
const
LinuxWorkflow
(),
Logger:
()
=>
platform
.
isWindows
?
WindowsStdoutLogger
()
:
StdoutLogger
(),
MacOSWorkflow:
()
=>
const
MacOSWorkflow
(),
MDnsObservatoryDiscovery:
()
=>
MDnsObservatoryDiscovery
(),
OperatingSystemUtils:
()
=>
OperatingSystemUtils
(),
ProcessUtils:
()
=>
ProcessUtils
(),
SimControl:
()
=>
SimControl
(),
...
...
packages/flutter_tools/lib/src/ios/devices.dart
View file @
0b24a5a2
...
...
@@ -19,6 +19,7 @@ import '../build_info.dart';
import
'../convert.dart'
;
import
'../device.dart'
;
import
'../globals.dart'
;
import
'../mdns_discovery.dart'
;
import
'../project.dart'
;
import
'../protocol_discovery.dart'
;
import
'../reporting/reporting.dart'
;
...
...
@@ -345,7 +346,6 @@ class IOSDevice extends Device {
ipv6:
ipv6
,
);
}
final
int
installationResult
=
await
IOSDeploy
.
instance
.
runApp
(
deviceId:
id
,
bundlePath:
bundle
.
path
,
...
...
@@ -363,16 +363,36 @@ class IOSDevice extends Device {
return
LaunchResult
.
succeeded
();
}
Uri
localUri
;
try
{
printTrace
(
'Application launched on the device. Waiting for observatory port.'
);
final
Uri
localUri
=
await
observatoryDiscovery
.
uri
;
return
LaunchResult
.
succeeded
(
observatoryUri:
localUri
);
localUri
=
await
MDnsObservatoryDiscovery
.
instance
.
getObservatoryUri
(
package
.
id
,
this
,
ipv6
,
debuggingOptions
.
observatoryPort
,
);
if
(
localUri
!=
null
)
{
return
LaunchResult
.
succeeded
(
observatoryUri:
localUri
);
}
}
catch
(
error
)
{
printError
(
'Failed to establish a debug connection with
$id
:
$error
'
);
}
// Fallback to manual protocol discovery
printTrace
(
'mDNS lookup failed, attempting fallback to reading device log.'
);
try
{
printTrace
(
'Waiting for observatory port.'
);
localUri
=
await
observatoryDiscovery
.
uri
;
if
(
localUri
!=
null
)
{
return
LaunchResult
.
succeeded
(
observatoryUri:
localUri
);
}
}
catch
(
error
)
{
printError
(
'Failed to establish a debug connection with
$id
:
$error
'
);
return
LaunchResult
.
failed
();
}
finally
{
await
observatoryDiscovery
?.
cancel
();
}
return
LaunchResult
.
failed
();
}
finally
{
installStatus
.
stop
();
}
...
...
packages/flutter_tools/lib/src/mdns_discovery.dart
0 → 100644
View file @
0b24a5a2
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:async'
;
import
'package:meta/meta.dart'
;
import
'package:multicast_dns/multicast_dns.dart'
;
import
'base/common.dart'
;
import
'base/context.dart'
;
import
'base/io.dart'
;
import
'device.dart'
;
import
'globals.dart'
;
/// A wrapper around [MDnsClient] to find a Dart observatory instance.
class
MDnsObservatoryDiscovery
{
/// Creates a new [MDnsObservatoryDiscovery] object.
///
/// The [client] parameter will be defaulted to a new [MDnsClient] if null.
/// 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
})
:
client
=
mdnsClient
??
MDnsClient
();
/// The [MDnsClient] used to do a lookup.
final
MDnsClient
client
;
@visibleForTesting
static
const
String
dartObservatoryName
=
'_dartobservatory._tcp.local'
;
static
MDnsObservatoryDiscovery
get
instance
=>
context
.
get
<
MDnsObservatoryDiscovery
>();
/// Executes an mDNS query for a Dart Observatory.
///
/// 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
/// the bundle ID.
///
/// If it is not null, this method will find the port and authentication code
/// of the Dart Observatory for that application. If it cannot find a Dart
/// Observatory matching that application identifier, it will call
/// [throwToolExit].
///
/// If it is null and there are multiple ports available, the user will be
/// prompted with a list of available observatory ports and asked to select
/// one.
///
/// If it is null and there is only one available instance of Observatory,
/// it will return that instance's information regardless of what application
/// the Observatory instance is for.
Future
<
MDnsObservatoryDiscoveryResult
>
query
({
String
applicationId
})
async
{
printStatus
(
'Checking for advertised Dart observatories...'
);
try
{
await
client
.
start
();
final
List
<
PtrResourceRecord
>
pointerRecords
=
await
client
.
lookup
<
PtrResourceRecord
>(
ResourceRecordQuery
.
serverPointer
(
dartObservatoryName
),
)
.
toList
();
if
(
pointerRecords
.
isEmpty
)
{
return
null
;
}
// We have no guarantee that we won't get multiple hits from the same
// service on this.
final
List
<
String
>
uniqueDomainNames
=
pointerRecords
.
map
<
String
>((
PtrResourceRecord
record
)
=>
record
.
domainName
)
.
toSet
()
.
toList
();
String
domainName
;
if
(
applicationId
!=
null
)
{
for
(
String
name
in
uniqueDomainNames
)
{
if
(
name
.
toLowerCase
().
startsWith
(
applicationId
.
toLowerCase
()))
{
domainName
=
name
;
break
;
}
}
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
{
domainName
=
pointerRecords
[
0
].
domainName
;
}
printStatus
(
'Checking for available port on
$domainName
'
);
// Here, if we get more than one, it should just be a duplicate.
final
List
<
SrvResourceRecord
>
srv
=
await
client
.
lookup
<
SrvResourceRecord
>(
ResourceRecordQuery
.
service
(
domainName
),
)
.
toList
();
if
(
srv
.
isEmpty
)
{
return
null
;
}
if
(
srv
.
length
>
1
)
{
printError
(
'Unexpectedly found more than one observatory report for
$domainName
'
'- using first one (
${srv.first.port}
).'
);
}
printStatus
(
'Checking for authentication code for
$domainName
'
);
final
List
<
TxtResourceRecord
>
txt
=
await
client
.
lookup
<
TxtResourceRecord
>(
ResourceRecordQuery
.
text
(
domainName
),
)
?.
toList
();
if
(
txt
==
null
||
txt
.
isEmpty
)
{
return
MDnsObservatoryDiscoveryResult
(
srv
.
first
.
port
,
''
);
}
String
authCode
=
''
;
const
String
authCodePrefix
=
'authCode='
;
String
raw
=
txt
.
first
.
text
;
// TXT has a format of [<length byte>, text], so if the length is 2,
// that means that TXT is empty.
if
(
raw
.
length
>
2
)
{
// Remove length byte from raw txt.
raw
=
raw
.
substring
(
1
);
if
(
raw
.
startsWith
(
authCodePrefix
))
{
authCode
=
raw
.
substring
(
authCodePrefix
.
length
);
// The Observatory currently expects a trailing '/' as part of the
// URI, otherwise an invalid authentication code response is given.
if
(!
authCode
.
endsWith
(
'/'
))
{
authCode
+=
'/'
;
}
}
}
return
MDnsObservatoryDiscoveryResult
(
srv
.
first
.
port
,
authCode
);
}
finally
{
client
.
stop
();
}
}
Future
<
Uri
>
getObservatoryUri
(
String
applicationId
,
Device
device
,
[
bool
usesIpv6
=
false
,
int
observatoryPort
])
async
{
final
MDnsObservatoryDiscoveryResult
result
=
await
query
(
applicationId:
applicationId
);
Uri
observatoryUri
;
if
(
result
!=
null
)
{
final
String
host
=
usesIpv6
?
InternetAddress
.
loopbackIPv6
.
address
:
InternetAddress
.
loopbackIPv4
.
address
;
observatoryUri
=
await
buildObservatoryUri
(
device
,
host
,
result
.
port
,
observatoryPort
,
result
.
authCode
);
}
return
observatoryUri
;
}
}
class
MDnsObservatoryDiscoveryResult
{
MDnsObservatoryDiscoveryResult
(
this
.
port
,
this
.
authCode
);
final
int
port
;
final
String
authCode
;
}
Future
<
Uri
>
buildObservatoryUri
(
Device
device
,
String
host
,
int
devicePort
,
[
int
observatoryPort
,
String
authCode
])
async
{
String
path
=
'/'
;
if
(
authCode
!=
null
)
{
path
=
authCode
;
}
// Not having a trailing slash can cause problems in some situations.
// Ensure that there's one present.
if
(!
path
.
endsWith
(
'/'
))
{
path
+=
'/'
;
}
final
int
localPort
=
observatoryPort
??
await
device
.
portForwarder
.
forward
(
devicePort
);
return
Uri
(
scheme:
'http'
,
host:
host
,
port:
localPort
,
path:
path
);
}
packages/flutter_tools/test/general.shard/commands/attach_test.dart
View file @
0b24a5a2
...
...
@@ -13,11 +13,12 @@ import 'package:flutter_tools/src/base/terminal.dart';
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/commands/attach.dart'
;
import
'package:flutter_tools/src/device.dart'
;
import
'package:flutter_tools/src/ios/devices.dart'
;
import
'package:flutter_tools/src/mdns_discovery.dart'
;
import
'package:flutter_tools/src/resident_runner.dart'
;
import
'package:flutter_tools/src/run_hot.dart'
;
import
'package:meta/meta.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:multicast_dns/multicast_dns.dart'
;
import
'../../src/common.dart'
;
import
'../../src/context.dart'
;
...
...
@@ -261,7 +262,7 @@ void main() {
when
(
portForwarder
.
unforward
(
any
))
.
thenAnswer
((
_
)
async
=>
null
);
when
(
mockHotRunner
.
attach
(
appStartedCompleter:
anyNamed
(
'appStartedCompleter'
)))
.
thenAnswer
((
_
)
async
=>
0
);
.
thenAnswer
((
_
)
async
=>
0
);
when
(
mockHotRunnerFactory
.
build
(
any
,
target:
anyNamed
(
'target'
),
...
...
@@ -466,137 +467,13 @@ void main() {
FileSystem:
()
=>
testFileSystem
,
});
});
group
(
'mDNS Discovery'
,
()
{
final
int
year3000
=
DateTime
(
3000
).
millisecondsSinceEpoch
;
MDnsClient
getMockClient
(
List
<
PtrResourceRecord
>
ptrRecords
,
Map
<
String
,
List
<
SrvResourceRecord
>>
srvResponse
,
)
{
final
MDnsClient
client
=
MockMDnsClient
();
when
(
client
.
lookup
<
PtrResourceRecord
>(
ResourceRecordQuery
.
serverPointer
(
MDnsObservatoryDiscovery
.
dartObservatoryName
),
)).
thenAnswer
((
_
)
=>
Stream
<
PtrResourceRecord
>.
fromIterable
(
ptrRecords
));
for
(
final
MapEntry
<
String
,
List
<
SrvResourceRecord
>>
entry
in
srvResponse
.
entries
)
{
when
(
client
.
lookup
<
SrvResourceRecord
>(
ResourceRecordQuery
.
service
(
entry
.
key
),
)).
thenAnswer
((
_
)
=>
Stream
<
SrvResourceRecord
>.
fromIterable
(
entry
.
value
));
}
return
client
;
}
testUsingContext
(
'No ports available'
,
()
async
{
final
MDnsClient
client
=
getMockClient
(<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{});
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
client
);
final
int
port
=
(
await
portDiscovery
.
query
())?.
port
;
expect
(
port
,
isNull
);
});
testUsingContext
(
'One port available, no appId'
,
()
async
{
final
MDnsClient
client
=
getMockClient
(
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
],
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
},
);
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
client
);
final
int
port
=
(
await
portDiscovery
.
query
())?.
port
;
expect
(
port
,
123
);
});
testUsingContext
(
'Multiple ports available, without appId'
,
()
async
{
final
MDnsClient
client
=
getMockClient
(
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
PtrResourceRecord
(
'baz'
,
year3000
,
domainName:
'fiz'
),
],
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
'fiz'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'fiz'
,
year3000
,
port:
321
,
weight:
1
,
priority:
1
,
target:
'local'
),
],
},
);
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
client
);
expect
(()
=>
portDiscovery
.
query
(),
throwsToolExit
());
});
testUsingContext
(
'Multiple ports available, with appId'
,
()
async
{
final
MDnsClient
client
=
getMockClient
(
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
PtrResourceRecord
(
'baz'
,
year3000
,
domainName:
'fiz'
),
],
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
'fiz'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'fiz'
,
year3000
,
port:
321
,
weight:
1
,
priority:
1
,
target:
'local'
),
],
},
);
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
client
);
final
int
port
=
(
await
portDiscovery
.
query
(
applicationId:
'fiz'
))?.
port
;
expect
(
port
,
321
);
});
testUsingContext
(
'Multiple ports available per process, with appId'
,
()
async
{
final
MDnsClient
client
=
getMockClient
(
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
PtrResourceRecord
(
'baz'
,
year3000
,
domainName:
'fiz'
),
],
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
year3000
,
port:
1234
,
weight:
1
,
priority:
1
,
target:
'appId'
),
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
'fiz'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'fiz'
,
year3000
,
port:
4321
,
weight:
1
,
priority:
1
,
target:
'local'
),
SrvResourceRecord
(
'fiz'
,
year3000
,
port:
321
,
weight:
1
,
priority:
1
,
target:
'local'
),
],
},
);
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
client
);
final
int
port
=
(
await
portDiscovery
.
query
(
applicationId:
'bar'
))?.
port
;
expect
(
port
,
1234
);
});
testUsingContext
(
'Query returns null'
,
()
async
{
final
MDnsClient
client
=
getMockClient
(
<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{},
);
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
client
);
final
int
port
=
(
await
portDiscovery
.
query
(
applicationId:
'bar'
))?.
port
;
expect
(
port
,
isNull
);
});
});
}
class
MockMDnsClient
extends
Mock
implements
MDnsClient
{}
class
MockPortForwarder
extends
Mock
implements
DevicePortForwarder
{}
class
MockHotRunner
extends
Mock
implements
HotRunner
{}
class
MockHotRunnerFactory
extends
Mock
implements
HotRunnerFactory
{}
class
MockIOSDevice
extends
Mock
implements
IOSDevice
{}
class
MockMDnsObservatoryDiscovery
extends
Mock
implements
MDnsObservatoryDiscovery
{}
class
MockPortForwarder
extends
Mock
implements
DevicePortForwarder
{}
class
StreamLogger
extends
Logger
{
@override
...
...
packages/flutter_tools/test/general.shard/ios/devices_test.dart
View file @
0b24a5a2
...
...
@@ -21,6 +21,7 @@ import 'package:flutter_tools/src/ios/devices.dart';
import
'package:flutter_tools/src/ios/mac.dart'
;
import
'package:flutter_tools/src/ios/ios_workflow.dart'
;
import
'package:flutter_tools/src/macos/xcode.dart'
;
import
'package:flutter_tools/src/mdns_discovery.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:meta/meta.dart'
;
import
'package:mockito/mockito.dart'
;
...
...
@@ -39,6 +40,7 @@ class MockDirectory extends Mock implements Directory {}
class
MockFileSystem
extends
Mock
implements
FileSystem
{}
class
MockIMobileDevice
extends
Mock
implements
IMobileDevice
{}
class
MockIOSDeploy
extends
Mock
implements
IOSDeploy
{}
class
MockMDnsObservatoryDiscovery
extends
Mock
implements
MDnsObservatoryDiscovery
{}
class
MockXcode
extends
Mock
implements
Xcode
{}
class
MockFile
extends
Mock
implements
File
{}
class
MockPortForwarder
extends
Mock
implements
DevicePortForwarder
{}
...
...
@@ -78,6 +80,7 @@ void main() {
MockFileSystem
mockFileSystem
;
MockProcessManager
mockProcessManager
;
MockDeviceLogReader
mockLogReader
;
MockMDnsObservatoryDiscovery
mockMDnsObservatoryDiscovery
;
MockPortForwarder
mockPortForwarder
;
MockIMobileDevice
mockIMobileDevice
;
MockIOSDeploy
mockIosDeploy
;
...
...
@@ -106,6 +109,7 @@ void main() {
mockCache
=
MockCache
();
when
(
mockCache
.
dyLdLibEntry
).
thenReturn
(
libraryEntry
);
mockFileSystem
=
MockFileSystem
();
mockMDnsObservatoryDiscovery
=
MockMDnsObservatoryDiscovery
();
mockProcessManager
=
MockProcessManager
();
mockLogReader
=
MockDeviceLogReader
();
mockPortForwarder
=
MockPortForwarder
();
...
...
@@ -161,16 +165,18 @@ void main() {
Cache
.
enableLocking
();
});
testUsingContext
(
' succeeds in debug mode'
,
()
async
{
testUsingContext
(
' succeeds in debug mode
via mDNS
'
,
()
async
{
final
IOSDevice
device
=
IOSDevice
(
'123'
);
device
.
portForwarder
=
mockPortForwarder
;
device
.
setLogReader
(
mockApp
,
mockLogReader
);
// Now that the reader is used, start writing messages to it.
Timer
.
run
(()
{
mockLogReader
.
addLine
(
'Foo'
);
mockLogReader
.
addLine
(
'Observatory listening on http://127.0.0.1:
$devicePort
'
);
});
final
Uri
uri
=
Uri
(
scheme:
'http'
,
host:
'127.0.0.1'
,
port:
1234
,
path:
'observatory'
,
);
when
(
mockMDnsObservatoryDiscovery
.
getObservatoryUri
(
any
,
any
,
any
))
.
thenAnswer
((
Invocation
invocation
)
=>
Future
<
Uri
>.
value
(
uri
));
final
LaunchResult
launchResult
=
await
device
.
startApp
(
mockApp
,
prebuiltApplication:
true
,
...
...
@@ -184,29 +190,41 @@ void main() {
Artifacts:
()
=>
mockArtifacts
,
Cache:
()
=>
mockCache
,
FileSystem:
()
=>
mockFileSystem
,
MDnsObservatoryDiscovery:
()
=>
mockMDnsObservatoryDiscovery
,
Platform:
()
=>
macPlatform
,
ProcessManager:
()
=>
mockProcessManager
,
});
testUsingContext
(
' succeeds in
release mode
'
,
()
async
{
testUsingContext
(
' succeeds in
debug mode when mDNS fails by falling back to manual protocol discovery
'
,
()
async
{
final
IOSDevice
device
=
IOSDevice
(
'123'
);
device
.
portForwarder
=
mockPortForwarder
;
device
.
setLogReader
(
mockApp
,
mockLogReader
);
// Now that the reader is used, start writing messages to it.
Timer
.
run
(()
{
mockLogReader
.
addLine
(
'Foo'
);
mockLogReader
.
addLine
(
'Observatory listening on http://127.0.0.1:
$devicePort
'
);
});
when
(
mockMDnsObservatoryDiscovery
.
getObservatoryUri
(
any
,
any
,
any
))
.
thenAnswer
((
Invocation
invocation
)
=>
Future
<
Uri
>.
value
(
null
));
final
LaunchResult
launchResult
=
await
device
.
startApp
(
mockApp
,
prebuiltApplication:
true
,
debuggingOptions:
DebuggingOptions
.
disabled
(
const
BuildInfo
(
BuildMode
.
release
,
null
)),
debuggingOptions:
DebuggingOptions
.
enabled
(
const
BuildInfo
(
BuildMode
.
debug
,
null
)),
platformArgs:
<
String
,
dynamic
>{},
);
expect
(
launchResult
.
started
,
isTrue
);
expect
(
launchResult
.
hasObservatory
,
is
Fals
e
);
expect
(
launchResult
.
hasObservatory
,
is
Tru
e
);
expect
(
await
device
.
stopApp
(
mockApp
),
isFalse
);
},
overrides:
<
Type
,
Generator
>{
Artifacts:
()
=>
mockArtifacts
,
Cache:
()
=>
mockCache
,
FileSystem:
()
=>
mockFileSystem
,
MDnsObservatoryDiscovery:
()
=>
mockMDnsObservatoryDiscovery
,
Platform:
()
=>
macPlatform
,
ProcessManager:
()
=>
mockProcessManager
,
});
testUsingContext
(
' fails in debug mode when Observatory URI is malformed'
,
()
async
{
testUsingContext
(
' fails in debug mode when
mDNS fails and when
Observatory URI is malformed'
,
()
async
{
final
IOSDevice
device
=
IOSDevice
(
'123'
);
device
.
portForwarder
=
mockPortForwarder
;
device
.
setLogReader
(
mockApp
,
mockLogReader
);
...
...
@@ -216,6 +234,8 @@ void main() {
mockLogReader
.
addLine
(
'Foo'
);
mockLogReader
.
addLine
(
'Observatory listening on http:/:/127.0.0.1:
$devicePort
'
);
});
when
(
mockMDnsObservatoryDiscovery
.
getObservatoryUri
(
any
,
any
,
any
))
.
thenAnswer
((
Invocation
invocation
)
=>
Future
<
Uri
>.
value
(
null
));
final
LaunchResult
launchResult
=
await
device
.
startApp
(
mockApp
,
prebuiltApplication:
true
,
...
...
@@ -224,6 +244,25 @@ void main() {
);
expect
(
launchResult
.
started
,
isFalse
);
expect
(
launchResult
.
hasObservatory
,
isFalse
);
},
overrides:
<
Type
,
Generator
>{
Artifacts:
()
=>
mockArtifacts
,
Cache:
()
=>
mockCache
,
FileSystem:
()
=>
mockFileSystem
,
MDnsObservatoryDiscovery:
()
=>
mockMDnsObservatoryDiscovery
,
Platform:
()
=>
macPlatform
,
ProcessManager:
()
=>
mockProcessManager
,
});
testUsingContext
(
' succeeds in release mode'
,
()
async
{
final
IOSDevice
device
=
IOSDevice
(
'123'
);
final
LaunchResult
launchResult
=
await
device
.
startApp
(
mockApp
,
prebuiltApplication:
true
,
debuggingOptions:
DebuggingOptions
.
disabled
(
const
BuildInfo
(
BuildMode
.
release
,
null
)),
platformArgs:
<
String
,
dynamic
>{},
);
expect
(
launchResult
.
started
,
isTrue
);
expect
(
launchResult
.
hasObservatory
,
isFalse
);
expect
(
await
device
.
stopApp
(
mockApp
),
isFalse
);
},
overrides:
<
Type
,
Generator
>{
Artifacts:
()
=>
mockArtifacts
,
Cache:
()
=>
mockCache
,
...
...
packages/flutter_tools/test/general.shard/mdns_discovery_test.dart
0 → 100644
View file @
0b24a5a2
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:async'
;
import
'package:flutter_tools/src/mdns_discovery.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:multicast_dns/multicast_dns.dart'
;
import
'../src/common.dart'
;
import
'../src/context.dart'
;
void
main
(
)
{
group
(
'mDNS Discovery'
,
()
{
final
int
year3000
=
DateTime
(
3000
).
millisecondsSinceEpoch
;
MDnsClient
getMockClient
(
List
<
PtrResourceRecord
>
ptrRecords
,
Map
<
String
,
List
<
SrvResourceRecord
>>
srvResponse
,
)
{
final
MDnsClient
client
=
MockMDnsClient
();
when
(
client
.
lookup
<
PtrResourceRecord
>(
ResourceRecordQuery
.
serverPointer
(
MDnsObservatoryDiscovery
.
dartObservatoryName
),
)).
thenAnswer
((
_
)
=>
Stream
<
PtrResourceRecord
>.
fromIterable
(
ptrRecords
));
for
(
final
MapEntry
<
String
,
List
<
SrvResourceRecord
>>
entry
in
srvResponse
.
entries
)
{
when
(
client
.
lookup
<
SrvResourceRecord
>(
ResourceRecordQuery
.
service
(
entry
.
key
),
)).
thenAnswer
((
_
)
=>
Stream
<
SrvResourceRecord
>.
fromIterable
(
entry
.
value
));
}
return
client
;
}
testUsingContext
(
'No ports available'
,
()
async
{
final
MDnsClient
client
=
getMockClient
(<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{});
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
client
);
final
int
port
=
(
await
portDiscovery
.
query
())?.
port
;
expect
(
port
,
isNull
);
});
testUsingContext
(
'One port available, no appId'
,
()
async
{
final
MDnsClient
client
=
getMockClient
(
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
],
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
},
);
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
client
);
final
int
port
=
(
await
portDiscovery
.
query
())?.
port
;
expect
(
port
,
123
);
});
testUsingContext
(
'Multiple ports available, without appId'
,
()
async
{
final
MDnsClient
client
=
getMockClient
(
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
PtrResourceRecord
(
'baz'
,
year3000
,
domainName:
'fiz'
),
],
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
'fiz'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'fiz'
,
year3000
,
port:
321
,
weight:
1
,
priority:
1
,
target:
'local'
),
],
},
);
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
client
);
expect
(()
=>
portDiscovery
.
query
(),
throwsToolExit
());
});
testUsingContext
(
'Multiple ports available, with appId'
,
()
async
{
final
MDnsClient
client
=
getMockClient
(
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
PtrResourceRecord
(
'baz'
,
year3000
,
domainName:
'fiz'
),
],
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
'fiz'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'fiz'
,
year3000
,
port:
321
,
weight:
1
,
priority:
1
,
target:
'local'
),
],
},
);
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
client
);
final
int
port
=
(
await
portDiscovery
.
query
(
applicationId:
'fiz'
))?.
port
;
expect
(
port
,
321
);
});
testUsingContext
(
'Multiple ports available per process, with appId'
,
()
async
{
final
MDnsClient
client
=
getMockClient
(
<
PtrResourceRecord
>[
PtrResourceRecord
(
'foo'
,
year3000
,
domainName:
'bar'
),
PtrResourceRecord
(
'baz'
,
year3000
,
domainName:
'fiz'
),
],
<
String
,
List
<
SrvResourceRecord
>>{
'bar'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'bar'
,
year3000
,
port:
1234
,
weight:
1
,
priority:
1
,
target:
'appId'
),
SrvResourceRecord
(
'bar'
,
year3000
,
port:
123
,
weight:
1
,
priority:
1
,
target:
'appId'
),
],
'fiz'
:
<
SrvResourceRecord
>[
SrvResourceRecord
(
'fiz'
,
year3000
,
port:
4321
,
weight:
1
,
priority:
1
,
target:
'local'
),
SrvResourceRecord
(
'fiz'
,
year3000
,
port:
321
,
weight:
1
,
priority:
1
,
target:
'local'
),
],
},
);
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
client
);
final
int
port
=
(
await
portDiscovery
.
query
(
applicationId:
'bar'
))?.
port
;
expect
(
port
,
1234
);
});
testUsingContext
(
'Query returns null'
,
()
async
{
final
MDnsClient
client
=
getMockClient
(
<
PtrResourceRecord
>[],
<
String
,
List
<
SrvResourceRecord
>>{},
);
final
MDnsObservatoryDiscovery
portDiscovery
=
MDnsObservatoryDiscovery
(
mdnsClient:
client
);
final
int
port
=
(
await
portDiscovery
.
query
(
applicationId:
'bar'
))?.
port
;
expect
(
port
,
isNull
);
});
});
}
class
MockMDnsClient
extends
Mock
implements
MDnsClient
{}
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