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
f640ad69
Unverified
Commit
f640ad69
authored
May 27, 2020
by
Jonah Williams
Committed by
GitHub
May 27, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tools] ensure emulator command does not crash with missing avdmanager (#57703)
parent
ffc56ff7
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
533 additions
and
306 deletions
+533
-306
android_emulator.dart
packages/flutter_tools/lib/src/android/android_emulator.dart
+110
-61
android_workflow.dart
packages/flutter_tools/lib/src/android/android_workflow.dart
+9
-3
daemon.dart
packages/flutter_tools/lib/src/commands/daemon.dart
+8
-1
emulators.dart
packages/flutter_tools/lib/src/commands/emulators.dart
+1
-1
context_runner.dart
packages/flutter_tools/lib/src/context_runner.dart
+10
-2
emulator.dart
packages/flutter_tools/lib/src/emulator.dart
+61
-33
ios_emulators.dart
packages/flutter_tools/lib/src/ios/ios_emulators.dart
+3
-0
android_device_discovery_test.dart
.../general.shard/android/android_device_discovery_test.dart
+9
-3
android_emulator_test.dart
...ols/test/general.shard/android/android_emulator_test.dart
+100
-70
emulator_test.dart
packages/flutter_tools/test/general.shard/emulator_test.dart
+222
-132
No files found.
packages/flutter_tools/lib/src/android/android_emulator.dart
View file @
f640ad69
...
@@ -5,36 +5,131 @@
...
@@ -5,36 +5,131 @@
import
'dart:async'
;
import
'dart:async'
;
import
'package:meta/meta.dart'
;
import
'package:meta/meta.dart'
;
import
'package:process/process.dart'
;
import
'../android/android_sdk.dart'
;
import
'../android/android_sdk.dart'
;
import
'../android/android_workflow.dart'
;
import
'../android/android_workflow.dart'
;
import
'../base/common.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/process.dart'
;
import
'../base/process.dart'
;
import
'../base/utils.dart'
;
import
'../base/utils.dart'
;
import
'../convert.dart'
;
import
'../convert.dart'
;
import
'../device.dart'
;
import
'../device.dart'
;
import
'../emulator.dart'
;
import
'../emulator.dart'
;
import
'../globals.dart'
as
globals
;
import
'android_sdk.dart'
;
import
'android_sdk.dart'
;
class
AndroidEmulators
extends
EmulatorDiscovery
{
class
AndroidEmulators
extends
EmulatorDiscovery
{
AndroidEmulators
({
@required
AndroidSdk
androidSdk
,
@required
AndroidWorkflow
androidWorkflow
,
@required
FileSystem
fileSystem
,
@required
Logger
logger
,
@required
ProcessManager
processManager
,
})
:
_androidSdk
=
androidSdk
,
_androidWorkflow
=
androidWorkflow
,
_fileSystem
=
fileSystem
,
_logger
=
logger
,
_processManager
=
processManager
,
_processUtils
=
ProcessUtils
(
logger:
logger
,
processManager:
processManager
);
final
AndroidWorkflow
_androidWorkflow
;
final
AndroidSdk
_androidSdk
;
final
FileSystem
_fileSystem
;
final
Logger
_logger
;
final
ProcessManager
_processManager
;
final
ProcessUtils
_processUtils
;
@override
@override
bool
get
supportsPlatform
=>
true
;
bool
get
supportsPlatform
=>
true
;
@override
@override
bool
get
canListAnything
=>
androidWorkflow
.
canListEmulators
;
bool
get
canListAnything
=>
_androidWorkflow
.
canListEmulators
;
@override
bool
get
canLaunchAnything
=>
_androidWorkflow
.
canListEmulators
&&
_androidSdk
.
getAvdManagerPath
()
!=
null
;
@override
@override
Future
<
List
<
Emulator
>>
get
emulators
async
=>
getEmulatorAvds
();
Future
<
List
<
Emulator
>>
get
emulators
=>
_getEmulatorAvds
();
/// Return the list of available emulator AVDs.
Future
<
List
<
AndroidEmulator
>>
_getEmulatorAvds
()
async
{
final
String
emulatorPath
=
getEmulatorPath
(
_androidSdk
);
if
(
emulatorPath
==
null
)
{
return
<
AndroidEmulator
>[];
}
final
String
listAvdsOutput
=
(
await
_processUtils
.
run
(
<
String
>[
emulatorPath
,
'-list-avds'
])).
stdout
.
trim
();
final
List
<
AndroidEmulator
>
emulators
=
<
AndroidEmulator
>[];
if
(
listAvdsOutput
!=
null
)
{
_extractEmulatorAvdInfo
(
listAvdsOutput
,
emulators
);
}
return
emulators
;
}
/// Parse the given `emulator -list-avds` output in [text], and fill out the given list
/// of emulators by reading information from the relevant ini files.
void
_extractEmulatorAvdInfo
(
String
text
,
List
<
AndroidEmulator
>
emulators
)
{
for
(
final
String
id
in
text
.
trim
().
split
(
'
\n
'
).
where
((
String
l
)
=>
l
!=
''
))
{
emulators
.
add
(
_loadEmulatorInfo
(
id
));
}
}
AndroidEmulator
_loadEmulatorInfo
(
String
id
)
{
id
=
id
.
trim
();
final
String
avdPath
=
getAvdPath
();
final
AndroidEmulator
androidEmulatorWithoutProperties
=
AndroidEmulator
(
id
,
processManager:
_processManager
,
logger:
_logger
,
androidSdk:
_androidSdk
,
);
if
(
avdPath
==
null
)
{
return
androidEmulatorWithoutProperties
;
}
final
File
iniFile
=
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
avdPath
,
'
$id
.ini'
));
if
(!
iniFile
.
existsSync
())
{
return
androidEmulatorWithoutProperties
;
}
final
Map
<
String
,
String
>
ini
=
parseIniLines
(
iniFile
.
readAsLinesSync
());
if
(
ini
[
'path'
]
==
null
)
{
return
androidEmulatorWithoutProperties
;
}
final
File
configFile
=
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
ini
[
'path'
],
'config.ini'
));
if
(!
configFile
.
existsSync
())
{
return
androidEmulatorWithoutProperties
;
}
final
Map
<
String
,
String
>
properties
=
parseIniLines
(
configFile
.
readAsLinesSync
());
return
AndroidEmulator
(
id
,
properties:
properties
,
processManager:
_processManager
,
logger:
_logger
,
androidSdk:
_androidSdk
,
);
}
}
}
class
AndroidEmulator
extends
Emulator
{
class
AndroidEmulator
extends
Emulator
{
AndroidEmulator
(
String
id
,
[
this
.
_properties
])
AndroidEmulator
(
String
id
,
{
:
super
(
id
,
_properties
!=
null
&&
_properties
.
isNotEmpty
);
Map
<
String
,
String
>
properties
,
@required
Logger
logger
,
@required
AndroidSdk
androidSdk
,
@required
ProcessManager
processManager
,
})
:
_properties
=
properties
,
_logger
=
logger
,
_androidSdk
=
androidSdk
,
_processUtils
=
ProcessUtils
(
logger:
logger
,
processManager:
processManager
),
super
(
id
,
properties
!=
null
&&
properties
.
isNotEmpty
);
final
Map
<
String
,
String
>
_properties
;
final
Map
<
String
,
String
>
_properties
;
final
Logger
_logger
;
final
ProcessUtils
_processUtils
;
final
AndroidSdk
_androidSdk
;
// Android Studio uses the ID with underscores replaced with spaces
// Android Studio uses the ID with underscores replaced with spaces
// for the name if displayname is not set so we do the same.
// for the name if displayname is not set so we do the same.
...
@@ -54,8 +149,8 @@ class AndroidEmulator extends Emulator {
...
@@ -54,8 +149,8 @@ class AndroidEmulator extends Emulator {
@override
@override
Future
<
void
>
launch
()
async
{
Future
<
void
>
launch
()
async
{
final
Process
process
=
await
processUtils
.
start
(
final
Process
process
=
await
_
processUtils
.
start
(
<
String
>[
getEmulatorPath
(
globals
.
androidSdk
),
'-avd'
,
id
],
<
String
>[
getEmulatorPath
(
_
androidSdk
),
'-avd'
,
id
],
);
);
// Record output from the emulator process.
// Record output from the emulator process.
...
@@ -81,7 +176,7 @@ class AndroidEmulator extends Emulator {
...
@@ -81,7 +176,7 @@ class AndroidEmulator extends Emulator {
bool
earlyFailure
=
true
;
bool
earlyFailure
=
true
;
unawaited
(
process
.
exitCode
.
then
((
int
status
)
async
{
unawaited
(
process
.
exitCode
.
then
((
int
status
)
async
{
if
(
status
==
0
)
{
if
(
status
==
0
)
{
globals
.
printTrace
(
'The Android emulator exited successfully'
);
_logger
.
printTrace
(
'The Android emulator exited successfully'
);
return
;
return
;
}
}
// Make sure the process' stdout and stderr are drained.
// Make sure the process' stdout and stderr are drained.
...
@@ -89,18 +184,18 @@ class AndroidEmulator extends Emulator {
...
@@ -89,18 +184,18 @@ class AndroidEmulator extends Emulator {
unawaited
(
stdoutSubscription
.
cancel
());
unawaited
(
stdoutSubscription
.
cancel
());
unawaited
(
stderrSubscription
.
cancel
());
unawaited
(
stderrSubscription
.
cancel
());
if
(
stdoutList
.
isNotEmpty
)
{
if
(
stdoutList
.
isNotEmpty
)
{
globals
.
printTrace
(
'Android emulator stdout:'
);
_logger
.
printTrace
(
'Android emulator stdout:'
);
stdoutList
.
forEach
(
globals
.
printTrace
);
stdoutList
.
forEach
(
_logger
.
printTrace
);
}
}
if
(!
earlyFailure
&&
stderrList
.
isEmpty
)
{
if
(!
earlyFailure
&&
stderrList
.
isEmpty
)
{
globals
.
printStatus
(
'The Android emulator exited with code
$status
'
);
_logger
.
printStatus
(
'The Android emulator exited with code
$status
'
);
return
;
return
;
}
}
final
String
when
=
earlyFailure
?
'during startup'
:
'after startup'
;
final
String
when
=
earlyFailure
?
'during startup'
:
'after startup'
;
globals
.
printError
(
'The Android emulator exited with code
$status
$when
'
);
_logger
.
printError
(
'The Android emulator exited with code
$status
$when
'
);
globals
.
printError
(
'Android emulator stderr:'
);
_logger
.
printError
(
'Android emulator stderr:'
);
stderrList
.
forEach
(
globals
.
printError
);
stderrList
.
forEach
(
_logger
.
printError
);
globals
.
printError
(
'Address these issues and try again.'
);
_logger
.
printError
(
'Address these issues and try again.'
);
}));
}));
// Wait a few seconds for the emulator to start.
// Wait a few seconds for the emulator to start.
...
@@ -110,52 +205,6 @@ class AndroidEmulator extends Emulator {
...
@@ -110,52 +205,6 @@ class AndroidEmulator extends Emulator {
}
}
}
}
/// Return the list of available emulator AVDs.
List
<
AndroidEmulator
>
getEmulatorAvds
()
{
final
String
emulatorPath
=
getEmulatorPath
(
globals
.
androidSdk
);
if
(
emulatorPath
==
null
)
{
return
<
AndroidEmulator
>[];
}
final
String
listAvdsOutput
=
processUtils
.
runSync
(
<
String
>[
emulatorPath
,
'-list-avds'
]).
stdout
.
trim
();
final
List
<
AndroidEmulator
>
emulators
=
<
AndroidEmulator
>[];
if
(
listAvdsOutput
!=
null
)
{
extractEmulatorAvdInfo
(
listAvdsOutput
,
emulators
);
}
return
emulators
;
}
/// Parse the given `emulator -list-avds` output in [text], and fill out the given list
/// of emulators by reading information from the relevant ini files.
void
extractEmulatorAvdInfo
(
String
text
,
List
<
AndroidEmulator
>
emulators
)
{
for
(
final
String
id
in
text
.
trim
().
split
(
'
\n
'
).
where
((
String
l
)
=>
l
!=
''
))
{
emulators
.
add
(
_loadEmulatorInfo
(
id
));
}
}
AndroidEmulator
_loadEmulatorInfo
(
String
id
)
{
id
=
id
.
trim
();
final
String
avdPath
=
getAvdPath
();
if
(
avdPath
!=
null
)
{
final
File
iniFile
=
globals
.
fs
.
file
(
globals
.
fs
.
path
.
join
(
avdPath
,
'
$id
.ini'
));
if
(
iniFile
.
existsSync
())
{
final
Map
<
String
,
String
>
ini
=
parseIniLines
(
iniFile
.
readAsLinesSync
());
if
(
ini
[
'path'
]
!=
null
)
{
final
File
configFile
=
globals
.
fs
.
file
(
globals
.
fs
.
path
.
join
(
ini
[
'path'
],
'config.ini'
));
if
(
configFile
.
existsSync
())
{
final
Map
<
String
,
String
>
properties
=
parseIniLines
(
configFile
.
readAsLinesSync
());
return
AndroidEmulator
(
id
,
properties
);
}
}
}
}
return
AndroidEmulator
(
id
);
}
@visibleForTesting
@visibleForTesting
Map
<
String
,
String
>
parseIniLines
(
List
<
String
>
contents
)
{
Map
<
String
,
String
>
parseIniLines
(
List
<
String
>
contents
)
{
...
...
packages/flutter_tools/lib/src/android/android_workflow.dart
View file @
f640ad69
...
@@ -44,17 +44,23 @@ final RegExp licenseNotAccepted = RegExp(r'licenses? not accepted', caseSensitiv
...
@@ -44,17 +44,23 @@ final RegExp licenseNotAccepted = RegExp(r'licenses? not accepted', caseSensitiv
final
RegExp
licenseAccepted
=
RegExp
(
r'All SDK package licenses accepted.'
);
final
RegExp
licenseAccepted
=
RegExp
(
r'All SDK package licenses accepted.'
);
class
AndroidWorkflow
implements
Workflow
{
class
AndroidWorkflow
implements
Workflow
{
AndroidWorkflow
({
@required
AndroidSdk
androidSdk
,
})
:
_androidSdk
=
androidSdk
;
final
AndroidSdk
_androidSdk
;
@override
@override
bool
get
appliesToHostPlatform
=>
true
;
bool
get
appliesToHostPlatform
=>
true
;
@override
@override
bool
get
canListDevices
=>
getAdbPath
(
globals
.
androidSdk
)
!=
null
;
bool
get
canListDevices
=>
getAdbPath
(
_
androidSdk
)
!=
null
;
@override
@override
bool
get
canLaunchDevices
=>
globals
.
androidSdk
!=
null
&&
globals
.
androidSdk
.
validateSdkWellFormed
().
isEmpty
;
bool
get
canLaunchDevices
=>
_androidSdk
!=
null
&&
_
androidSdk
.
validateSdkWellFormed
().
isEmpty
;
@override
@override
bool
get
canListEmulators
=>
getEmulatorPath
(
globals
.
androidSdk
)
!=
null
;
bool
get
canListEmulators
=>
getEmulatorPath
(
_
androidSdk
)
!=
null
;
}
}
class
AndroidValidator
extends
DoctorValidator
{
class
AndroidValidator
extends
DoctorValidator
{
...
...
packages/flutter_tools/lib/src/commands/daemon.dart
View file @
f640ad69
...
@@ -7,6 +7,7 @@ import 'dart:async';
...
@@ -7,6 +7,7 @@ import 'dart:async';
import
'package:meta/meta.dart'
;
import
'package:meta/meta.dart'
;
import
'package:uuid/uuid.dart'
;
import
'package:uuid/uuid.dart'
;
import
'../android/android_workflow.dart'
;
import
'../base/common.dart'
;
import
'../base/common.dart'
;
import
'../base/context.dart'
;
import
'../base/context.dart'
;
import
'../base/file_system.dart'
;
import
'../base/file_system.dart'
;
...
@@ -1039,7 +1040,13 @@ class EmulatorDomain extends Domain {
...
@@ -1039,7 +1040,13 @@ class EmulatorDomain extends Domain {
registerHandler
(
'create'
,
create
);
registerHandler
(
'create'
,
create
);
}
}
EmulatorManager
emulators
=
EmulatorManager
();
EmulatorManager
emulators
=
EmulatorManager
(
fileSystem:
globals
.
fs
,
logger:
globals
.
logger
,
androidSdk:
globals
.
androidSdk
,
processManager:
globals
.
processManager
,
androidWorkflow:
androidWorkflow
,
);
Future
<
List
<
Map
<
String
,
dynamic
>>>
getEmulators
([
Map
<
String
,
dynamic
>
args
])
async
{
Future
<
List
<
Map
<
String
,
dynamic
>>>
getEmulators
([
Map
<
String
,
dynamic
>
args
])
async
{
final
List
<
Emulator
>
list
=
await
emulators
.
getAllAvailableEmulators
();
final
List
<
Emulator
>
list
=
await
emulators
.
getAllAvailableEmulators
();
...
...
packages/flutter_tools/lib/src/commands/emulators.dart
View file @
f640ad69
...
@@ -104,7 +104,7 @@ class EmulatorsCommand extends FlutterCommand {
...
@@ -104,7 +104,7 @@ class EmulatorsCommand extends FlutterCommand {
void
_printEmulatorList
(
List
<
Emulator
>
emulators
,
String
message
)
{
void
_printEmulatorList
(
List
<
Emulator
>
emulators
,
String
message
)
{
globals
.
printStatus
(
'
$message
\n
'
);
globals
.
printStatus
(
'
$message
\n
'
);
Emulator
.
printEmulators
(
emulators
);
Emulator
.
printEmulators
(
emulators
,
globals
.
logger
);
_printAdditionalInfo
(
showCreateInstruction:
true
,
showRunInstruction:
true
);
_printAdditionalInfo
(
showCreateInstruction:
true
,
showRunInstruction:
true
);
}
}
...
...
packages/flutter_tools/lib/src/context_runner.dart
View file @
f640ad69
...
@@ -79,7 +79,9 @@ Future<T> runInContext<T>(
...
@@ -79,7 +79,9 @@ Future<T> runInContext<T>(
processManager:
globals
.
processManager
,
processManager:
globals
.
processManager
,
userMessages:
globals
.
userMessages
,
userMessages:
globals
.
userMessages
,
),
),
AndroidWorkflow:
()
=>
AndroidWorkflow
(),
AndroidWorkflow:
()
=>
AndroidWorkflow
(
androidSdk:
globals
.
androidSdk
,
),
ApplicationPackageFactory:
()
=>
ApplicationPackageFactory
(),
ApplicationPackageFactory:
()
=>
ApplicationPackageFactory
(),
Artifacts:
()
=>
CachedArtifacts
(
Artifacts:
()
=>
CachedArtifacts
(
fileSystem:
globals
.
fs
,
fileSystem:
globals
.
fs
,
...
@@ -125,7 +127,13 @@ Future<T> runInContext<T>(
...
@@ -125,7 +127,13 @@ Future<T> runInContext<T>(
DeviceManager:
()
=>
DeviceManager
(),
DeviceManager:
()
=>
DeviceManager
(),
Doctor:
()
=>
Doctor
(
logger:
globals
.
logger
),
Doctor:
()
=>
Doctor
(
logger:
globals
.
logger
),
DoctorValidatorsProvider:
()
=>
DoctorValidatorsProvider
.
defaultInstance
,
DoctorValidatorsProvider:
()
=>
DoctorValidatorsProvider
.
defaultInstance
,
EmulatorManager:
()
=>
EmulatorManager
(),
EmulatorManager:
()
=>
EmulatorManager
(
androidSdk:
globals
.
androidSdk
,
processManager:
globals
.
processManager
,
logger:
globals
.
logger
,
fileSystem:
globals
.
fs
,
androidWorkflow:
androidWorkflow
,
),
FeatureFlags:
()
=>
const
FeatureFlags
(),
FeatureFlags:
()
=>
const
FeatureFlags
(),
FlutterVersion:
()
=>
FlutterVersion
(
const
SystemClock
()),
FlutterVersion:
()
=>
FlutterVersion
(
const
SystemClock
()),
FuchsiaArtifacts:
()
=>
FuchsiaArtifacts
.
find
(),
FuchsiaArtifacts:
()
=>
FuchsiaArtifacts
.
find
(),
...
...
packages/flutter_tools/lib/src/emulator.dart
View file @
f640ad69
...
@@ -6,28 +6,49 @@ import 'dart:async';
...
@@ -6,28 +6,49 @@ import 'dart:async';
import
'dart:math'
as
math
;
import
'dart:math'
as
math
;
import
'package:meta/meta.dart'
;
import
'package:meta/meta.dart'
;
import
'package:process/process.dart'
;
import
'android/android_emulator.dart'
;
import
'android/android_emulator.dart'
;
import
'android/android_sdk.dart'
;
import
'android/android_sdk.dart'
;
import
'android/android_workflow.dart'
;
import
'base/context.dart'
;
import
'base/context.dart'
;
import
'base/file_system.dart'
;
import
'base/logger.dart'
;
import
'base/process.dart'
;
import
'base/process.dart'
;
import
'device.dart'
;
import
'device.dart'
;
import
'globals.dart'
as
globals
;
import
'ios/ios_emulators.dart'
;
import
'ios/ios_emulators.dart'
;
EmulatorManager
get
emulatorManager
=>
context
.
get
<
EmulatorManager
>();
EmulatorManager
get
emulatorManager
=>
context
.
get
<
EmulatorManager
>();
/// A class to get all available emulators.
/// A class to get all available emulators.
class
EmulatorManager
{
class
EmulatorManager
{
/// Constructing EmulatorManager is cheap; they only do expensive work if some
EmulatorManager
({
/// of their methods are called.
@required
AndroidSdk
androidSdk
,
EmulatorManager
()
{
@required
Logger
logger
,
// Register the known discoverers.
@required
ProcessManager
processManager
,
_emulatorDiscoverers
.
add
(
AndroidEmulators
());
@required
AndroidWorkflow
androidWorkflow
,
_emulatorDiscoverers
.
add
(
IOSEmulators
());
@required
FileSystem
fileSystem
,
})
:
_androidSdk
=
androidSdk
,
_processUtils
=
ProcessUtils
(
logger:
logger
,
processManager:
processManager
),
_androidEmulators
=
AndroidEmulators
(
androidSdk:
androidSdk
,
logger:
logger
,
processManager:
processManager
,
fileSystem:
fileSystem
,
androidWorkflow:
androidWorkflow
)
{
_emulatorDiscoverers
.
add
(
_androidEmulators
);
}
}
final
List
<
EmulatorDiscovery
>
_emulatorDiscoverers
=
<
EmulatorDiscovery
>[];
final
AndroidSdk
_androidSdk
;
final
AndroidEmulators
_androidEmulators
;
final
ProcessUtils
_processUtils
;
// Constructing EmulatorManager is cheap; they only do expensive work if some
// of their methods are called.
final
List
<
EmulatorDiscovery
>
_emulatorDiscoverers
=
<
EmulatorDiscovery
>[
IOSEmulators
(),
];
Future
<
List
<
Emulator
>>
getEmulatorsMatching
(
String
searchText
)
async
{
Future
<
List
<
Emulator
>>
getEmulatorsMatching
(
String
searchText
)
async
{
final
List
<
Emulator
>
emulators
=
await
getAllAvailableEmulators
();
final
List
<
Emulator
>
emulators
=
await
getAllAvailableEmulators
();
...
@@ -64,7 +85,7 @@ class EmulatorManager {
...
@@ -64,7 +85,7 @@ class EmulatorManager {
/// Return the list of all available emulators.
/// Return the list of all available emulators.
Future
<
CreateEmulatorResult
>
createEmulator
({
String
name
})
async
{
Future
<
CreateEmulatorResult
>
createEmulator
({
String
name
})
async
{
if
(
name
==
null
||
name
==
''
)
{
if
(
name
==
null
||
name
.
isEmpty
)
{
const
String
autoName
=
'flutter_emulator'
;
const
String
autoName
=
'flutter_emulator'
;
// Don't use getEmulatorsMatching here, as it will only return one
// Don't use getEmulatorsMatching here, as it will only return one
// if there's an exact match and we need all those with this prefix
// if there's an exact match and we need all those with this prefix
...
@@ -80,6 +101,11 @@ class EmulatorManager {
...
@@ -80,6 +101,11 @@ class EmulatorManager {
name
=
'
${autoName}
_
${++suffix}
'
;
name
=
'
${autoName}
_
${++suffix}
'
;
}
}
}
}
if
(!
_androidEmulators
.
canLaunchAnything
)
{
return
CreateEmulatorResult
(
name
,
success:
false
,
error:
'avdmanager is missing from the Android SDK'
);
}
final
String
device
=
await
_getPreferredAvailableDevice
();
final
String
device
=
await
_getPreferredAvailableDevice
();
if
(
device
==
null
)
{
if
(
device
==
null
)
{
...
@@ -113,17 +139,15 @@ class EmulatorManager {
...
@@ -113,17 +139,15 @@ class EmulatorManager {
.
join
(
'
\n
'
)
.
join
(
'
\n
'
)
.
trim
();
.
trim
();
}
}
final
RunResult
runResult
=
await
_processUtils
.
run
(<
String
>[
final
List
<
String
>
args
=
<
String
>[
getAvdManagerPath
(
_androidSdk
),
getAvdManagerPath
(
globals
.
androidSdk
),
'create'
,
'create'
,
'avd'
,
'avd'
,
'-n'
,
name
,
'-n'
,
name
,
'-k'
,
sdkId
,
'-k'
,
sdkId
,
'-d'
,
device
,
'-d'
,
device
,
],
environment:
_androidSdk
?.
sdkManagerEnv
,
];
);
final
RunResult
runResult
=
processUtils
.
runSync
(
args
,
environment:
globals
.
androidSdk
?.
sdkManagerEnv
);
return
CreateEmulatorResult
(
return
CreateEmulatorResult
(
name
,
name
,
success:
runResult
.
exitCode
==
0
,
success:
runResult
.
exitCode
==
0
,
...
@@ -136,15 +160,16 @@ class EmulatorManager {
...
@@ -136,15 +160,16 @@ class EmulatorManager {
'pixel'
,
'pixel'
,
'pixel_xl'
,
'pixel_xl'
,
];
];
Future
<
String
>
_getPreferredAvailableDevice
()
async
{
Future
<
String
>
_getPreferredAvailableDevice
()
async
{
final
List
<
String
>
args
=
<
String
>[
final
List
<
String
>
args
=
<
String
>[
getAvdManagerPath
(
globals
.
androidSdk
),
getAvdManagerPath
(
_
androidSdk
),
'list'
,
'list'
,
'device'
,
'device'
,
'-c'
,
'-c'
,
];
];
final
RunResult
runResult
=
processUtils
.
runSync
(
args
,
final
RunResult
runResult
=
await
_processUtils
.
run
(
args
,
environment:
globals
.
androidSdk
?.
sdkManagerEnv
);
environment:
_
androidSdk
?.
sdkManagerEnv
);
if
(
runResult
.
exitCode
!=
0
)
{
if
(
runResult
.
exitCode
!=
0
)
{
return
null
;
return
null
;
}
}
...
@@ -160,29 +185,30 @@ class EmulatorManager {
...
@@ -160,29 +185,30 @@ class EmulatorManager {
);
);
}
}
RegExp
androidApiVersion
=
RegExp
(
r';android-(\d+);'
);
static
final
RegExp
_androidApiVersion
=
RegExp
(
r';android-(\d+);'
);
Future
<
String
>
_getPreferredSdkId
()
async
{
Future
<
String
>
_getPreferredSdkId
()
async
{
// It seems that to get the available list of images, we need to send a
// It seems that to get the available list of images, we need to send a
// request to create without the image and it'll provide us a list :-(
// request to create without the image and it'll provide us a list :-(
final
List
<
String
>
args
=
<
String
>[
final
List
<
String
>
args
=
<
String
>[
getAvdManagerPath
(
globals
.
androidSdk
),
getAvdManagerPath
(
_
androidSdk
),
'create'
,
'create'
,
'avd'
,
'avd'
,
'-n'
,
'temp'
,
'-n'
,
'temp'
,
];
];
final
RunResult
runResult
=
processUtils
.
runSync
(
args
,
final
RunResult
runResult
=
await
_processUtils
.
run
(
args
,
environment:
globals
.
androidSdk
?.
sdkManagerEnv
);
environment:
_
androidSdk
?.
sdkManagerEnv
);
// Get the list of IDs that match our criteria
// Get the list of IDs that match our criteria
final
List
<
String
>
availableIDs
=
runResult
.
stderr
final
List
<
String
>
availableIDs
=
runResult
.
stderr
.
split
(
'
\n
'
)
.
split
(
'
\n
'
)
.
where
((
String
l
)
=>
androidApiVersion
.
hasMatch
(
l
))
.
where
((
String
l
)
=>
_
androidApiVersion
.
hasMatch
(
l
))
.
where
((
String
l
)
=>
l
.
contains
(
'system-images'
))
.
where
((
String
l
)
=>
l
.
contains
(
'system-images'
))
.
where
((
String
l
)
=>
l
.
contains
(
'google_apis_playstore'
))
.
where
((
String
l
)
=>
l
.
contains
(
'google_apis_playstore'
))
.
toList
();
.
toList
();
final
List
<
int
>
availableApiVersions
=
availableIDs
final
List
<
int
>
availableApiVersions
=
availableIDs
.
map
<
String
>((
String
id
)
=>
androidApiVersion
.
firstMatch
(
id
).
group
(
1
))
.
map
<
String
>((
String
id
)
=>
_
androidApiVersion
.
firstMatch
(
id
).
group
(
1
))
.
map
<
int
>((
String
apiVersion
)
=>
int
.
parse
(
apiVersion
))
.
map
<
int
>((
String
apiVersion
)
=>
int
.
parse
(
apiVersion
))
.
toList
();
.
toList
();
...
@@ -209,10 +235,12 @@ class EmulatorManager {
...
@@ -209,10 +235,12 @@ class EmulatorManager {
abstract
class
EmulatorDiscovery
{
abstract
class
EmulatorDiscovery
{
bool
get
supportsPlatform
;
bool
get
supportsPlatform
;
/// Whether this emulator discovery is capable of listing any emulators given the
/// Whether this emulator discovery is capable of listing any emulators.
/// current environment configuration.
bool
get
canListAnything
;
bool
get
canListAnything
;
/// Whether this emulator discovery is capabale of launching new emulators.
bool
get
canLaunchAnything
;
Future
<
List
<
Emulator
>>
get
emulators
;
Future
<
List
<
Emulator
>>
get
emulators
;
}
}
...
@@ -280,8 +308,8 @@ abstract class Emulator {
...
@@ -280,8 +308,8 @@ abstract class Emulator {
.
toList
();
.
toList
();
}
}
static
void
printEmulators
(
List
<
Emulator
>
emulators
)
{
static
void
printEmulators
(
List
<
Emulator
>
emulators
,
Logger
logger
)
{
descriptions
(
emulators
).
forEach
(
globals
.
printStatus
);
descriptions
(
emulators
).
forEach
(
logger
.
printStatus
);
}
}
}
}
...
...
packages/flutter_tools/lib/src/ios/ios_emulators.dart
View file @
f640ad69
...
@@ -19,6 +19,9 @@ class IOSEmulators extends EmulatorDiscovery {
...
@@ -19,6 +19,9 @@ class IOSEmulators extends EmulatorDiscovery {
@override
@override
Future
<
List
<
Emulator
>>
get
emulators
async
=>
getEmulators
();
Future
<
List
<
Emulator
>>
get
emulators
async
=>
getEmulators
();
@override
bool
get
canLaunchAnything
=>
canListAnything
;
}
}
class
IOSEmulator
extends
Emulator
{
class
IOSEmulator
extends
Emulator
{
...
...
packages/flutter_tools/test/general.shard/android/android_device_discovery_test.dart
View file @
f640ad69
...
@@ -20,7 +20,9 @@ void main() {
...
@@ -20,7 +20,9 @@ void main() {
final
AndroidDevices
androidDevices
=
AndroidDevices
(
final
AndroidDevices
androidDevices
=
AndroidDevices
(
androidSdk:
MockAndroidSdk
(
null
),
androidSdk:
MockAndroidSdk
(
null
),
logger:
BufferLogger
.
test
(),
logger:
BufferLogger
.
test
(),
androidWorkflow:
AndroidWorkflow
(),
androidWorkflow:
AndroidWorkflow
(
androidSdk:
MockAndroidSdk
(
null
),
),
processManager:
FakeProcessManager
.
list
(<
FakeCommand
>[]),
processManager:
FakeProcessManager
.
list
(<
FakeCommand
>[]),
);
);
...
@@ -39,7 +41,9 @@ void main() {
...
@@ -39,7 +41,9 @@ void main() {
final
AndroidDevices
androidDevices
=
AndroidDevices
(
final
AndroidDevices
androidDevices
=
AndroidDevices
(
androidSdk:
MockAndroidSdk
(),
androidSdk:
MockAndroidSdk
(),
logger:
BufferLogger
.
test
(),
logger:
BufferLogger
.
test
(),
androidWorkflow:
AndroidWorkflow
(),
androidWorkflow:
AndroidWorkflow
(
androidSdk:
MockAndroidSdk
(),
),
processManager:
processManager
,
processManager:
processManager
,
);
);
...
@@ -57,7 +61,9 @@ void main() {
...
@@ -57,7 +61,9 @@ void main() {
final
AndroidDevices
androidDevices
=
AndroidDevices
(
final
AndroidDevices
androidDevices
=
AndroidDevices
(
androidSdk:
MockAndroidSdk
(),
androidSdk:
MockAndroidSdk
(),
logger:
BufferLogger
.
test
(),
logger:
BufferLogger
.
test
(),
androidWorkflow:
AndroidWorkflow
(),
androidWorkflow:
AndroidWorkflow
(
androidSdk:
MockAndroidSdk
(),
),
processManager:
processManager
,
processManager:
processManager
,
);
);
...
...
packages/flutter_tools/test/general.shard/android/android_emulator_test.dart
View file @
f640ad69
...
@@ -4,12 +4,11 @@
...
@@ -4,12 +4,11 @@
import
'dart:async'
;
import
'dart:async'
;
import
'package:file/file.dart'
;
import
'package:file/memory.dart'
;
import
'package:flutter_tools/src/android/android_sdk.dart'
import
'package:flutter_tools/src/android/android_sdk.dart'
show
getEmulatorPath
,
AndroidSdk
;
show
getEmulatorPath
;
import
'package:flutter_tools/src/android/android_emulator.dart'
;
import
'package:flutter_tools/src/android/android_emulator.dart'
;
import
'package:flutter_tools/src/base/common.dart'
;
import
'package:flutter_tools/src/base/common.dart'
;
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/device.dart'
;
import
'package:flutter_tools/src/device.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:quiver/testing/async.dart'
;
import
'package:quiver/testing/async.dart'
;
...
@@ -19,24 +18,42 @@ import '../../src/context.dart';
...
@@ -19,24 +18,42 @@ import '../../src/context.dart';
import
'../../src/fake_process_manager.dart'
;
import
'../../src/fake_process_manager.dart'
;
import
'../../src/mocks.dart'
show
MockAndroidSdk
;
import
'../../src/mocks.dart'
show
MockAndroidSdk
;
const
String
emulatorID
=
'i1234'
;
const
String
errorText
=
'[Android emulator test error]'
;
const
List
<
String
>
kEmulatorLaunchCommand
=
<
String
>[
'emulator'
,
'-avd'
,
emulatorID
,
];
void
main
(
)
{
void
main
(
)
{
group
(
'android_emulator'
,
()
{
group
(
'android_emulator'
,
()
{
test
Using
Context
(
'flags emulators without config'
,
()
{
test
Without
Context
(
'flags emulators without config'
,
()
{
const
String
emulatorID
=
'1234'
;
const
String
emulatorID
=
'1234'
;
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
);
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
,
logger:
BufferLogger
.
test
(),
processManager:
FakeProcessManager
.
any
(),
androidSdk:
MockAndroidSdk
(),
);
expect
(
emulator
.
id
,
emulatorID
);
expect
(
emulator
.
id
,
emulatorID
);
expect
(
emulator
.
hasConfig
,
false
);
expect
(
emulator
.
hasConfig
,
false
);
});
});
testUsingContext
(
'flags emulators with config'
,
()
{
testWithoutContext
(
'flags emulators with config'
,
()
{
const
String
emulatorID
=
'1234'
;
const
String
emulatorID
=
'1234'
;
final
AndroidEmulator
emulator
=
AndroidEmulator
(
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
,
emulatorID
,
const
<
String
,
String
>{
'name'
:
'test'
},
properties:
const
<
String
,
String
>{
'name'
:
'test'
},
logger:
BufferLogger
.
test
(),
processManager:
FakeProcessManager
.
any
(),
androidSdk:
MockAndroidSdk
(),
);
);
expect
(
emulator
.
id
,
emulatorID
);
expect
(
emulator
.
id
,
emulatorID
);
expect
(
emulator
.
hasConfig
,
true
);
expect
(
emulator
.
hasConfig
,
true
);
});
});
testUsingContext
(
'reads expected metadata'
,
()
{
testWithoutContext
(
'reads expected metadata'
,
()
{
const
String
emulatorID
=
'1234'
;
const
String
emulatorID
=
'1234'
;
const
String
manufacturer
=
'Me'
;
const
String
manufacturer
=
'Me'
;
const
String
displayName
=
'The best one'
;
const
String
displayName
=
'The best one'
;
...
@@ -44,33 +61,57 @@ void main() {
...
@@ -44,33 +61,57 @@ void main() {
'hw.device.manufacturer'
:
manufacturer
,
'hw.device.manufacturer'
:
manufacturer
,
'avd.ini.displayname'
:
displayName
,
'avd.ini.displayname'
:
displayName
,
};
};
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
,
properties
);
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
,
properties:
properties
,
logger:
BufferLogger
.
test
(),
processManager:
FakeProcessManager
.
any
(),
androidSdk:
MockAndroidSdk
(),
);
expect
(
emulator
.
id
,
emulatorID
);
expect
(
emulator
.
id
,
emulatorID
);
expect
(
emulator
.
name
,
displayName
);
expect
(
emulator
.
name
,
displayName
);
expect
(
emulator
.
manufacturer
,
manufacturer
);
expect
(
emulator
.
manufacturer
,
manufacturer
);
expect
(
emulator
.
category
,
Category
.
mobile
);
expect
(
emulator
.
category
,
Category
.
mobile
);
expect
(
emulator
.
platformType
,
PlatformType
.
android
);
expect
(
emulator
.
platformType
,
PlatformType
.
android
);
});
});
testUsingContext
(
'prefers displayname for name'
,
()
{
testWithoutContext
(
'prefers displayname for name'
,
()
{
const
String
emulatorID
=
'1234'
;
const
String
emulatorID
=
'1234'
;
const
String
displayName
=
'The best one'
;
const
String
displayName
=
'The best one'
;
final
Map
<
String
,
String
>
properties
=
<
String
,
String
>{
final
Map
<
String
,
String
>
properties
=
<
String
,
String
>{
'avd.ini.displayname'
:
displayName
,
'avd.ini.displayname'
:
displayName
,
};
};
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
,
properties
);
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
,
properties:
properties
,
logger:
BufferLogger
.
test
(),
processManager:
FakeProcessManager
.
any
(),
androidSdk:
MockAndroidSdk
(),
);
expect
(
emulator
.
name
,
displayName
);
expect
(
emulator
.
name
,
displayName
);
});
});
testUsingContext
(
'uses cleaned up ID if no displayname is set'
,
()
{
testWithoutContext
(
'uses cleaned up ID if no displayname is set'
,
()
{
// Android Studio uses the ID with underscores replaced with spaces
// Android Studio uses the ID with underscores replaced with spaces
// for the name if displayname is not set so we do the same.
// for the name if displayname is not set so we do the same.
const
String
emulatorID
=
'This_is_my_ID'
;
const
String
emulatorID
=
'This_is_my_ID'
;
final
Map
<
String
,
String
>
properties
=
<
String
,
String
>{
final
Map
<
String
,
String
>
properties
=
<
String
,
String
>{
'avd.ini.notadisplayname'
:
'this is not a display name'
,
'avd.ini.notadisplayname'
:
'this is not a display name'
,
};
};
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
,
properties
);
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
,
properties:
properties
,
logger:
BufferLogger
.
test
(),
processManager:
FakeProcessManager
.
any
(),
androidSdk:
MockAndroidSdk
(),
);
expect
(
emulator
.
name
,
'This is my ID'
);
expect
(
emulator
.
name
,
'This is my ID'
);
});
});
testUsingContext
(
'parses ini files'
,
()
{
testWithoutContext
(
'parses ini files'
,
()
{
const
String
iniFile
=
'''
const
String
iniFile
=
'''
hw.device.name=My Test Name
hw.device.name=My Test Name
#hw.device.name=Bad Name
#hw.device.name=Bad Name
...
@@ -79,6 +120,7 @@ void main() {
...
@@ -79,6 +120,7 @@ void main() {
avd.ini.displayname = dispName
avd.ini.displayname = dispName
'''
;
'''
;
final
Map
<
String
,
String
>
results
=
parseIniLines
(
iniFile
.
split
(
'
\n
'
));
final
Map
<
String
,
String
>
results
=
parseIniLines
(
iniFile
.
split
(
'
\n
'
));
expect
(
results
[
'hw.device.name'
],
'My Test Name'
);
expect
(
results
[
'hw.device.name'
],
'My Test Name'
);
expect
(
results
[
'hw.device.manufacturer'
],
'Me'
);
expect
(
results
[
'hw.device.manufacturer'
],
'Me'
);
expect
(
results
[
'avd.ini.displayname'
],
'dispName'
);
expect
(
results
[
'avd.ini.displayname'
],
'dispName'
);
...
@@ -86,51 +128,24 @@ void main() {
...
@@ -86,51 +128,24 @@ void main() {
});
});
group
(
'Android emulator launch '
,
()
{
group
(
'Android emulator launch '
,
()
{
const
String
emulatorID
=
'i1234'
;
const
String
errorText
=
'[Android emulator test error]'
;
MockAndroidSdk
mockSdk
;
MockAndroidSdk
mockSdk
;
FakeProcessManager
successProcessManager
;
FakeProcessManager
errorProcessManager
;
FakeProcessManager
lateFailureProcessManager
;
MemoryFileSystem
fs
;
setUp
(()
{
setUp
(()
{
fs
=
MemoryFileSystem
();
mockSdk
=
MockAndroidSdk
();
mockSdk
=
MockAndroidSdk
();
when
(
mockSdk
.
emulatorPath
).
thenReturn
(
'emulator'
);
when
(
mockSdk
.
emulatorPath
).
thenReturn
(
'emulator'
);
const
List
<
String
>
command
=
<
String
>[
'emulator'
,
'-avd'
,
emulatorID
,
];
successProcessManager
=
FakeProcessManager
.
list
(<
FakeCommand
>[
const
FakeCommand
(
command:
command
),
]);
errorProcessManager
=
FakeProcessManager
.
list
(<
FakeCommand
>[
const
FakeCommand
(
command:
command
,
exitCode:
1
,
stderr:
errorText
,
stdout:
'dummy text'
,
duration:
Duration
(
seconds:
1
),
),
]);
lateFailureProcessManager
=
FakeProcessManager
.
list
(<
FakeCommand
>[
const
FakeCommand
(
command:
command
,
exitCode:
1
,
stderr:
''
,
stdout:
'dummy text'
,
duration:
Duration
(
seconds:
4
),
),
]);
});
});
testUsingContext
(
'succeeds'
,
()
async
{
testWithoutContext
(
'succeeds'
,
()
async
{
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
);
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
,
processManager:
FakeProcessManager
.
list
(<
FakeCommand
>[
const
FakeCommand
(
command:
kEmulatorLaunchCommand
),
]),
androidSdk:
mockSdk
,
logger:
BufferLogger
.
test
(),
);
expect
(
getEmulatorPath
(
mockSdk
),
mockSdk
.
emulatorPath
);
expect
(
getEmulatorPath
(
mockSdk
),
mockSdk
.
emulatorPath
);
final
Completer
<
void
>
completer
=
Completer
<
void
>();
final
Completer
<
void
>
completer
=
Completer
<
void
>();
FakeAsync
().
run
((
FakeAsync
time
)
{
FakeAsync
().
run
((
FakeAsync
time
)
{
unawaited
(
emulator
.
launch
().
whenComplete
(
completer
.
complete
));
unawaited
(
emulator
.
launch
().
whenComplete
(
completer
.
complete
));
...
@@ -138,15 +153,24 @@ void main() {
...
@@ -138,15 +153,24 @@ void main() {
time
.
flushMicrotasks
();
time
.
flushMicrotasks
();
});
});
await
completer
.
future
;
await
completer
.
future
;
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
successProcessManager
,
AndroidSdk:
()
=>
mockSdk
,
FileSystem:
()
=>
fs
,
});
});
testUsingContext
(
'prints error on failure'
,
()
async
{
testWithoutContext
(
'prints error on failure'
,
()
async
{
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
);
final
BufferLogger
logger
=
BufferLogger
.
test
();
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
,
processManager:
FakeProcessManager
.
list
(<
FakeCommand
>[
const
FakeCommand
(
command:
kEmulatorLaunchCommand
,
exitCode:
1
,
stderr:
errorText
,
stdout:
'dummy text'
,
duration:
Duration
(
seconds:
1
),
),
]),
androidSdk:
mockSdk
,
logger:
logger
,
);
final
Completer
<
void
>
completer
=
Completer
<
void
>();
final
Completer
<
void
>
completer
=
Completer
<
void
>();
FakeAsync
().
run
((
FakeAsync
time
)
{
FakeAsync
().
run
((
FakeAsync
time
)
{
unawaited
(
emulator
.
launch
().
whenComplete
(
completer
.
complete
));
unawaited
(
emulator
.
launch
().
whenComplete
(
completer
.
complete
));
...
@@ -155,15 +179,24 @@ void main() {
...
@@ -155,15 +179,24 @@ void main() {
});
});
await
completer
.
future
;
await
completer
.
future
;
expect
(
testLogger
.
errorText
,
contains
(
errorText
));
expect
(
logger
.
errorText
,
contains
(
errorText
));
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
errorProcessManager
,
AndroidSdk:
()
=>
mockSdk
,
FileSystem:
()
=>
fs
,
});
});
testUsingContext
(
'prints nothing on late failure with empty stderr'
,
()
async
{
testWithoutContext
(
'prints nothing on late failure with empty stderr'
,
()
async
{
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
);
final
BufferLogger
logger
=
BufferLogger
.
test
();
final
AndroidEmulator
emulator
=
AndroidEmulator
(
emulatorID
,
processManager:
FakeProcessManager
.
list
(<
FakeCommand
>[
const
FakeCommand
(
command:
kEmulatorLaunchCommand
,
exitCode:
1
,
stderr:
''
,
stdout:
'dummy text'
,
duration:
Duration
(
seconds:
4
),
),
]),
androidSdk:
mockSdk
,
logger:
logger
,
);
final
Completer
<
void
>
completer
=
Completer
<
void
>();
final
Completer
<
void
>
completer
=
Completer
<
void
>();
FakeAsync
().
run
((
FakeAsync
time
)
async
{
FakeAsync
().
run
((
FakeAsync
time
)
async
{
unawaited
(
emulator
.
launch
().
whenComplete
(
completer
.
complete
));
unawaited
(
emulator
.
launch
().
whenComplete
(
completer
.
complete
));
...
@@ -171,11 +204,8 @@ void main() {
...
@@ -171,11 +204,8 @@ void main() {
time
.
flushMicrotasks
();
time
.
flushMicrotasks
();
});
});
await
completer
.
future
;
await
completer
.
future
;
expect
(
testLogger
.
errorText
,
isEmpty
);
},
overrides:
<
Type
,
Generator
>{
expect
(
logger
.
errorText
,
isEmpty
);
ProcessManager:
()
=>
lateFailureProcessManager
,
AndroidSdk:
()
=>
mockSdk
,
FileSystem:
()
=>
fs
,
});
});
});
});
}
}
packages/flutter_tools/test/general.shard/emulator_test.dart
View file @
f640ad69
This diff is collapsed.
Click to expand it.
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