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
234952cf
Unverified
Commit
234952cf
authored
Jan 28, 2021
by
Jia Hao
Committed by
GitHub
Jan 28, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tools] Simplify `flutter test` internals (#74176)
parent
7c22f0d2
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
130 additions
and
144 deletions
+130
-144
flutter_platform.dart
packages/flutter_tools/lib/src/test/flutter_platform.dart
+123
-142
binding_fail_test.dart
packages/integration_test/test/binding_fail_test.dart
+7
-2
No files found.
packages/flutter_tools/lib/src/test/flutter_platform.dart
View file @
234952cf
...
...
@@ -225,9 +225,7 @@ autoUpdateGoldenFiles = $updateGoldens;
return buffer.toString();
}
enum InitialResult { crashed, connected }
enum TestResult { crashed, harnessBailed, testBailed }
enum _TestHarnessStatus { testerCrashed, finished }
typedef Finalizer = Future<void> Function();
...
...
@@ -466,7 +464,7 @@ class FlutterPlatform extends PlatformPlugin {
// We expect SIGKILL (9) because we tried to terminate it.
// It's negative because signals are returned as negative exit codes.
final
String
message
=
_getErrorMessage
(
_getExitCodeMessage
(
exitCode
,
'after tests finished'
),
_getExitCodeMessage
(
exitCode
),
testPath
,
shellPath
);
controller
.
sink
.
addError
(
message
);
...
...
@@ -474,21 +472,22 @@ class FlutterPlatform extends PlatformPlugin {
}
});
final
Completer
<
void
>
gotProcessObservatoryUri
=
Completer
<
void
>();
final
Completer
<
Uri
>
gotProcessObservatoryUri
=
Completer
<
Uri
>();
if
(!
enableObservatory
)
{
gotProcessObservatoryUri
.
complete
();
}
// Pipe stdout and stderr from the subprocess to our printStatus console.
// We also keep track of what observatory port the engine used, if any.
Uri
processObservatoryUri
;
final
Uri
ddsServiceUri
=
getDdsServiceUri
();
_pipeStandardStreamsToConsole
(
process
,
reportObservatoryUri:
(
Uri
detectedUri
)
async
{
assert
(
processObservatoryUri
==
null
);
assert
(
!
gotProcessObservatoryUri
.
isCompleted
);
assert
(
explicitObservatoryPort
==
null
||
explicitObservatoryPort
==
detectedUri
.
port
);
Uri
forwardingUri
;
if
(!
disableDds
)
{
final
DartDevelopmentService
dds
=
await
DartDevelopmentService
.
startDartDevelopmentService
(
detectedUri
,
...
...
@@ -496,30 +495,26 @@ class FlutterPlatform extends PlatformPlugin {
enableAuthCodes:
!
disableServiceAuthCodes
,
ipv6:
host
.
type
==
InternetAddressType
.
IPv6
,
);
processObservatory
Uri
=
dds
.
uri
;
forwarding
Uri
=
dds
.
uri
;
globals
.
printTrace
(
'Dart Development Service started at
${dds.uri}
, forwarding to VM service at
${dds.remoteVmServiceUri}
.'
);
}
else
{
processObservatory
Uri
=
detectedUri
;
forwarding
Uri
=
detectedUri
;
}
{
globals
.
printTrace
(
'Connecting to service protocol:
$
processObservatory
Uri
'
);
final
Future
<
vm_service
.
VmService
>
localVmService
=
connectToVmService
(
processObservatory
Uri
,
globals
.
printTrace
(
'Connecting to service protocol:
$
forwarding
Uri
'
);
final
Future
<
vm_service
.
VmService
>
localVmService
=
connectToVmService
(
forwarding
Uri
,
compileExpression:
_compileExpressionService
);
unawaited
(
localVmService
.
then
((
vm_service
.
VmService
vmservice
)
{
globals
.
printTrace
(
'Successfully connected to service protocol:
$
processObservatory
Uri
'
);
globals
.
printTrace
(
'Successfully connected to service protocol:
$
forwarding
Uri
'
);
}));
}
if
(
startPaused
&&
!
machine
)
{
globals
.
printStatus
(
'The test process has been started.'
);
globals
.
printStatus
(
'You can now connect to it using observatory. To connect, load the following Web site in your browser:'
);
globals
.
printStatus
(
'
$
processObservatory
Uri
'
);
globals
.
printStatus
(
'
$
forwarding
Uri
'
);
globals
.
printStatus
(
'You should first set appropriate breakpoints, then resume the test in the debugger.'
);
}
else
{
globals
.
printTrace
(
'test
$ourTestCount
: using observatory uri
$processObservatoryUri
from pid
${process.pid}
'
);
}
gotProcessObservatoryUri
.
complete
();
watcher
?.
handleStartedProcess
(
ProcessEvent
(
ourTestCount
,
process
,
processObservatoryUri
));
gotProcessObservatoryUri
.
complete
(
forwardingUri
);
},
);
...
...
@@ -527,124 +522,52 @@ class FlutterPlatform extends PlatformPlugin {
// The engine could crash, in which case process.exitCode will complete.
// The engine could connect to us, in which case webSocket.future will complete.
// The local test harness could get bored of us.
globals
.
printTrace
(
'test
$ourTestCount
: awaiting initial result for pid
${process.pid}
'
);
final
InitialResult
initialResult
=
await
Future
.
any
<
InitialResult
>(<
Future
<
InitialResult
>>[
process
.
exitCode
.
then
<
InitialResult
>((
int
exitCode
)
=>
InitialResult
.
crashed
),
gotProcessObservatoryUri
.
future
.
then
<
InitialResult
>((
void
value
)
{
return
webSocket
.
future
.
then
<
InitialResult
>(
(
WebSocket
webSocket
)
=>
InitialResult
.
connected
,
);
}),
globals
.
printTrace
(
'test
$ourTestCount
: awaiting connection to result for test process at pid
${process.pid}
'
);
final
_TestHarnessStatus
testHarnessStatus
=
await
Future
.
any
<
_TestHarnessStatus
>(<
Future
<
_TestHarnessStatus
>>[
process
.
exitCode
.
then
<
_TestHarnessStatus
>((
int
exitCode
)
=>
_TestHarnessStatus
.
testerCrashed
),
gotProcessObservatoryUri
.
future
.
then
<
_TestHarnessStatus
>((
Uri
processObservatoryUri
)
{
if
(
processObservatoryUri
!=
null
)
{
globals
.
printTrace
(
'test
$ourTestCount
: Observatory uri is available at
$processObservatoryUri
'
);
}
watcher
?.
handleStartedProcess
(
ProcessEvent
(
ourTestCount
,
process
,
processObservatoryUri
));
return
webSocket
.
future
.
then
<
_TestHarnessStatus
>((
WebSocket
remoteSocket
)
async
{
globals
.
printTrace
(
'test
$ourTestCount
: connected to test harness, now awaiting test result'
);
await
_controlTests
(
controller:
controller
,
remoteSocket:
remoteSocket
,
onError:
(
dynamic
error
,
StackTrace
stackTrace
)
{
// If you reach here, it's unlikely we're going to be able to really handle this well.
globals
.
printError
(
'test:
$testPath
\n
error:
$error
'
);
if
(!
controllerSinkClosed
)
{
controller
.
sink
.
addError
(
error
,
stackTrace
);
controller
.
sink
.
close
();
}
else
{
globals
.
printError
(
'unexpected error:
$error
'
);
}
}
);
await
watcher
?.
handleFinishedTest
(
ProcessEvent
(
ourTestCount
,
process
,
processObservatoryUri
));
return
_TestHarnessStatus
.
finished
;
});
})
]);
switch
(
initialResult
)
{
case
InitialResult
.
crashed
:
globals
.
printTrace
(
'test
$ourTestCount
: process with pid
${process.pid}
crashed before connecting to test harness'
);
final
int
exitCode
=
await
process
.
exitCode
;
subprocessActive
=
false
;
final
String
message
=
_getErrorMessage
(
_getExitCodeMessage
(
exitCode
,
'before connecting to test harness'
),
testPath
,
shellPath
);
controller
.
sink
.
addError
(
message
);
// Awaited for with 'sink.done' below.
unawaited
(
controller
.
sink
.
close
());
globals
.
printTrace
(
'test
$ourTestCount
: waiting for controller sink to close'
);
await
controller
.
sink
.
done
;
await
watcher
?.
handleTestCrashed
(
ProcessEvent
(
ourTestCount
,
process
));
break
;
case
InitialResult
.
connected
:
globals
.
printTrace
(
'test
$ourTestCount
: process with pid
${process.pid}
connected to test harness'
);
final
WebSocket
testSocket
=
await
webSocket
.
future
;
final
Completer
<
void
>
harnessDone
=
Completer
<
void
>();
final
StreamSubscription
<
dynamic
>
harnessToTest
=
controller
.
stream
.
listen
(
(
dynamic
event
)
{
testSocket
.
add
(
json
.
encode
(
event
));
},
onDone:
harnessDone
.
complete
,
onError:
(
dynamic
error
,
StackTrace
stack
)
{
// If you reach here, it's unlikely we're going to be able to really handle this well.
globals
.
printError
(
'test harness controller stream experienced an unexpected error
\n
test:
$testPath
\n
error:
$error
'
);
if
(!
controllerSinkClosed
)
{
controller
.
sink
.
addError
(
error
,
stack
);
controller
.
sink
.
close
();
}
else
{
globals
.
printError
(
'unexpected error from test harness controller stream:
$error
'
);
}
},
cancelOnError:
true
,
);
final
Completer
<
void
>
testDone
=
Completer
<
void
>();
final
StreamSubscription
<
dynamic
>
testToHarness
=
testSocket
.
listen
(
(
dynamic
encodedEvent
)
{
assert
(
encodedEvent
is
String
);
// we shouldn't ever get binary messages
controller
.
sink
.
add
(
json
.
decode
(
encodedEvent
as
String
));
},
onDone:
testDone
.
complete
,
onError:
(
dynamic
error
,
StackTrace
stack
)
{
// If you reach here, it's unlikely we're going to be able to really handle this well.
globals
.
printError
(
'test socket stream experienced an unexpected error
\n
test:
$testPath
\n
error:
$error
'
);
if
(!
controllerSinkClosed
)
{
controller
.
sink
.
addError
(
error
,
stack
);
controller
.
sink
.
close
();
}
else
{
globals
.
printError
(
'unexpected error from test socket stream:
$error
'
);
}
},
cancelOnError:
true
,
);
globals
.
printTrace
(
'test
$ourTestCount
: awaiting test result for pid
${process.pid}
'
);
final
TestResult
testResult
=
await
Future
.
any
<
TestResult
>(<
Future
<
TestResult
>>[
process
.
exitCode
.
then
<
TestResult
>((
int
exitCode
)
{
return
TestResult
.
crashed
;
}),
harnessDone
.
future
.
then
<
TestResult
>((
void
value
)
{
return
TestResult
.
harnessBailed
;
}),
testDone
.
future
.
then
<
TestResult
>((
void
value
)
{
return
TestResult
.
testBailed
;
}),
]);
await
Future
.
wait
<
void
>(<
Future
<
void
>>[
harnessToTest
.
cancel
(),
testToHarness
.
cancel
(),
]);
switch
(
testResult
)
{
case
TestResult
.
crashed
:
globals
.
printTrace
(
'test
$ourTestCount
: process with pid
${process.pid}
crashed'
);
final
int
exitCode
=
await
process
.
exitCode
;
subprocessActive
=
false
;
final
String
message
=
_getErrorMessage
(
_getExitCodeMessage
(
exitCode
,
'before test harness closed its WebSocket'
),
testPath
,
shellPath
);
controller
.
sink
.
addError
(
message
);
// Awaited for with 'sink.done' below.
unawaited
(
controller
.
sink
.
close
());
globals
.
printTrace
(
'test
$ourTestCount
: waiting for controller sink to close'
);
await
controller
.
sink
.
done
;
break
;
case
TestResult
.
harnessBailed
:
case
TestResult
.
testBailed
:
if
(
testResult
==
TestResult
.
harnessBailed
)
{
globals
.
printTrace
(
'test
$ourTestCount
: process with pid
${process.pid}
no longer needed by test harness'
);
}
else
{
assert
(
testResult
==
TestResult
.
testBailed
);
globals
.
printTrace
(
'test
$ourTestCount
: process with pid
${process.pid}
no longer needs test harness'
);
}
await
watcher
?.
handleFinishedTest
(
ProcessEvent
(
ourTestCount
,
process
,
processObservatoryUri
));
break
;
}
break
;
if
(
testHarnessStatus
==
_TestHarnessStatus
.
testerCrashed
)
{
globals
.
printTrace
(
'test
$ourTestCount
: process with pid
${process.pid}
crashed'
);
final
int
exitCode
=
await
process
.
exitCode
;
subprocessActive
=
false
;
final
String
message
=
_getErrorMessage
(
_getExitCodeMessage
(
exitCode
),
testPath
,
shellPath
);
controller
.
sink
.
addError
(
message
);
// Awaited for with 'sink.done' below in `finally`.
unawaited
(
controller
.
sink
.
close
());
globals
.
printTrace
(
'test
$ourTestCount
: waiting for controller sink to close'
);
await
controller
.
sink
.
done
;
await
watcher
?.
handleTestCrashed
(
ProcessEvent
(
ourTestCount
,
process
));
}
}
on
Exception
catch
(
error
,
stack
)
{
globals
.
printTrace
(
'test
$ourTestCount
: error caught during test;
${controllerSinkClosed ? "reporting to console" : "sending to test framework"}
'
);
...
...
@@ -878,22 +801,22 @@ class FlutterPlatform extends PlatformPlugin {
return
'
$what
\n
Test:
$testPath
\n
Shell:
$shellPath
\n\n
'
;
}
String
_getExitCodeMessage
(
int
exitCode
,
String
when
)
{
String
_getExitCodeMessage
(
int
exitCode
)
{
switch
(
exitCode
)
{
case
1
:
return
'Shell subprocess cleanly reported an error
$when
. Check the logs above for an error message.'
;
return
'Shell subprocess cleanly reported an error. Check the logs above for an error message.'
;
case
0
:
return
'Shell subprocess ended cleanly
$when
. Did main() call exit()?'
;
return
'Shell subprocess ended cleanly. Did main() call exit()?'
;
case
-
0x0f
:
// ProcessSignal.SIGTERM
return
'Shell subprocess crashed with SIGTERM (
$exitCode
)
$when
.'
;
return
'Shell subprocess crashed with SIGTERM (
$exitCode
).'
;
case
-
0x0b
:
// ProcessSignal.SIGSEGV
return
'Shell subprocess crashed with segmentation fault
$when
.'
;
return
'Shell subprocess crashed with segmentation fault.'
;
case
-
0x06
:
// ProcessSignal.SIGABRT
return
'Shell subprocess crashed with SIGABRT (
$exitCode
)
$when
.'
;
return
'Shell subprocess crashed with SIGABRT (
$exitCode
).'
;
case
-
0x02
:
// ProcessSignal.SIGINT
return
'Shell subprocess terminated by ^C (SIGINT,
$exitCode
)
$when
.'
;
return
'Shell subprocess terminated by ^C (SIGINT,
$exitCode
).'
;
default
:
return
'Shell subprocess crashed with unexpected exit code
$exitCode
$when
.'
;
return
'Shell subprocess crashed with unexpected exit code
$exitCode
.'
;
}
}
...
...
@@ -970,3 +893,61 @@ class _AsyncError {
final
dynamic
error
;
final
StackTrace
stack
;
}
/// Bridges the package:test controller and the remote tester.
///
/// Sets up a that allows the package:test test [controller] to communicate with
/// a [remoteSocket] that runs the test. The returned future completes when
/// either side is closed, which also indicates when the tests have finished.
Future
<
void
>
_controlTests
({
@required
StreamChannel
<
dynamic
>
controller
,
@required
WebSocket
remoteSocket
,
@required
void
Function
(
dynamic
,
StackTrace
)
onError
,
})
async
{
final
Completer
<
void
>
harnessDone
=
Completer
<
void
>();
final
StreamSubscription
<
dynamic
>
harnessToTest
=
controller
.
stream
.
listen
(
(
dynamic
event
)
{
remoteSocket
.
add
(
json
.
encode
(
event
));
},
onDone:
harnessDone
.
complete
,
onError:
(
dynamic
error
,
StackTrace
stack
)
{
globals
.
printError
(
'test harness controller stream experienced an unexpected error'
);
onError
(
error
,
stack
);
},
cancelOnError:
true
,
);
final
Completer
<
void
>
testDone
=
Completer
<
void
>();
final
StreamSubscription
<
dynamic
>
testToHarness
=
remoteSocket
.
listen
(
(
dynamic
encodedEvent
)
{
assert
(
encodedEvent
is
String
);
// we shouldn't ever get binary messages
controller
.
sink
.
add
(
json
.
decode
(
encodedEvent
as
String
));
},
onDone:
testDone
.
complete
,
onError:
(
dynamic
error
,
StackTrace
stack
)
{
globals
.
printError
(
'test socket stream experienced an unexpected error'
);
onError
(
error
,
stack
);
},
cancelOnError:
true
,
);
globals
.
printTrace
(
'waiting for test harness or tests to finish'
);
await
Future
.
any
<
void
>(<
Future
<
void
>>[
harnessDone
.
future
.
then
<
void
>((
void
value
)
{
globals
.
printTrace
(
'test process is no longer needed by test harness'
);
}),
testDone
.
future
.
then
<
void
>((
void
value
)
{
globals
.
printTrace
(
'test harness is no longer needed by test process'
);
}),
]);
await
Future
.
wait
<
void
>(<
Future
<
void
>>[
harnessToTest
.
cancel
(),
testToHarness
.
cancel
(),
]);
}
packages/integration_test/test/binding_fail_test.dart
View file @
234952cf
...
...
@@ -61,13 +61,18 @@ Future<Map<String, dynamic>> _runTest(String scriptPath) async {
final
String
testResults
=
(
await
process
.
stdout
.
transform
(
utf8
.
decoder
)
.
expand
((
String
text
)
=>
text
.
split
(
'
\n
'
))
.
map
((
String
line
)
{
.
map
<
dynamic
>
((
String
line
)
{
try
{
return
jsonDecode
(
line
)
as
Map
<
String
,
dynamic
>
;
return
jsonDecode
(
line
);
}
on
FormatException
{
// Only interested in test events which are JSON.
}
})
.
expand
<
Map
<
String
,
dynamic
>>((
dynamic
json
)
{
return
json
is
List
<
dynamic
>
?
json
.
cast
()
:
<
Map
<
String
,
dynamic
>>[
json
as
Map
<
String
,
dynamic
>];
})
.
where
((
Map
<
String
,
dynamic
>
testEvent
)
=>
testEvent
!=
null
&&
testEvent
[
'type'
]
==
'print'
)
.
map
((
Map
<
String
,
dynamic
>
printEvent
)
=>
printEvent
[
'message'
]
as
String
)
...
...
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