Do not stop flutter_tester if microtasks are still pending (flutter/engine#56432)
Flutter_tester has a task observer that checks whether the test's Dart code has finished execution. If Dart no longer has live ports but does have pending microtasks, then flutter_tester should continue running and force a drain of the microtask queue. Fixes https://github.com/flutter/flutter/issues/158129
This commit is contained in:
parent
d83dc6bdae
commit
ef5c2fc014
@ -169,6 +169,10 @@ void UIDartState::FlushMicrotasksNow() {
|
|||||||
microtask_queue_.RunMicrotasks();
|
microtask_queue_.RunMicrotasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UIDartState::HasPendingMicrotasks() {
|
||||||
|
return microtask_queue_.HasMicrotasks();
|
||||||
|
}
|
||||||
|
|
||||||
void UIDartState::AddOrRemoveTaskObserver(bool add) {
|
void UIDartState::AddOrRemoveTaskObserver(bool add) {
|
||||||
auto task_runner = context_.task_runners.GetUITaskRunner();
|
auto task_runner = context_.task_runners.GetUITaskRunner();
|
||||||
if (!task_runner) {
|
if (!task_runner) {
|
||||||
|
@ -130,6 +130,8 @@ class UIDartState : public tonic::DartState {
|
|||||||
|
|
||||||
void FlushMicrotasksNow();
|
void FlushMicrotasksNow();
|
||||||
|
|
||||||
|
bool HasPendingMicrotasks();
|
||||||
|
|
||||||
fml::WeakPtr<IOManager> GetIOManager() const;
|
fml::WeakPtr<IOManager> GetIOManager() const;
|
||||||
|
|
||||||
fml::RefPtr<flutter::SkiaUnrefQueue> GetSkiaUnrefQueue() const;
|
fml::RefPtr<flutter::SkiaUnrefQueue> GetSkiaUnrefQueue() const;
|
||||||
|
@ -511,6 +511,14 @@ bool RuntimeController::HasLivePorts() {
|
|||||||
return Dart_HasLivePorts();
|
return Dart_HasLivePorts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RuntimeController::HasPendingMicrotasks() {
|
||||||
|
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
|
||||||
|
if (!root_isolate) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return root_isolate->HasPendingMicrotasks();
|
||||||
|
}
|
||||||
|
|
||||||
tonic::DartErrorHandleType RuntimeController::GetLastError() {
|
tonic::DartErrorHandleType RuntimeController::GetLastError() {
|
||||||
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
|
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
|
||||||
return root_isolate ? root_isolate->GetLastError() : tonic::kNoError;
|
return root_isolate ? root_isolate->GetLastError() : tonic::kNoError;
|
||||||
|
@ -523,6 +523,15 @@ class RuntimeController : public PlatformConfigurationClient,
|
|||||||
///
|
///
|
||||||
bool HasLivePorts();
|
bool HasLivePorts();
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/// @brief Returns if the root isolate has any pending microtasks.
|
||||||
|
///
|
||||||
|
/// @return True if there are microtasks that have been queued but not
|
||||||
|
/// run, False otherwise. Return False if the root isolate is not
|
||||||
|
/// running as well.
|
||||||
|
///
|
||||||
|
bool HasPendingMicrotasks();
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
/// @brief Get the last error encountered by the microtask queue.
|
/// @brief Get the last error encountered by the microtask queue.
|
||||||
///
|
///
|
||||||
|
@ -293,6 +293,10 @@ bool Engine::UIIsolateHasLivePorts() {
|
|||||||
return runtime_controller_->HasLivePorts();
|
return runtime_controller_->HasLivePorts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Engine::UIIsolateHasPendingMicrotasks() {
|
||||||
|
return runtime_controller_->HasPendingMicrotasks();
|
||||||
|
}
|
||||||
|
|
||||||
tonic::DartErrorHandleType Engine::GetUIIsolateLastError() {
|
tonic::DartErrorHandleType Engine::GetUIIsolateLastError() {
|
||||||
return runtime_controller_->GetLastError();
|
return runtime_controller_->GetLastError();
|
||||||
}
|
}
|
||||||
|
@ -682,6 +682,15 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
|
|||||||
///
|
///
|
||||||
bool UIIsolateHasLivePorts();
|
bool UIIsolateHasLivePorts();
|
||||||
|
|
||||||
|
/// @brief Another signal of liveness is the presence of microtasks that
|
||||||
|
/// have been queued by the application but have not yet been
|
||||||
|
/// executed. Embedders may want to check for pending microtasks
|
||||||
|
/// and ensure that the microtask queue has been drained before
|
||||||
|
/// the embedder terminates.
|
||||||
|
///
|
||||||
|
/// @return Check if the root isolate has any pending microtasks.
|
||||||
|
bool UIIsolateHasPendingMicrotasks();
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
/// @brief Errors that are unhandled on the Dart message loop are kept
|
/// @brief Errors that are unhandled on the Dart message loop are kept
|
||||||
/// for further inspection till the next unhandled error comes
|
/// for further inspection till the next unhandled error comes
|
||||||
|
@ -710,6 +710,17 @@ bool Shell::EngineHasLivePorts() const {
|
|||||||
return weak_engine_->UIIsolateHasLivePorts();
|
return weak_engine_->UIIsolateHasLivePorts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Shell::EngineHasPendingMicrotasks() const {
|
||||||
|
FML_DCHECK(is_set_up_);
|
||||||
|
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
|
||||||
|
|
||||||
|
if (!weak_engine_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return weak_engine_->UIIsolateHasPendingMicrotasks();
|
||||||
|
}
|
||||||
|
|
||||||
bool Shell::IsSetup() const {
|
bool Shell::IsSetup() const {
|
||||||
return is_set_up_;
|
return is_set_up_;
|
||||||
}
|
}
|
||||||
|
@ -358,6 +358,17 @@ class Shell final : public PlatformView::Delegate,
|
|||||||
///
|
///
|
||||||
bool EngineHasLivePorts() const;
|
bool EngineHasLivePorts() const;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/// @brief Used by embedders to check if the Engine is running and has
|
||||||
|
/// any microtasks that have been queued but have not yet run.
|
||||||
|
/// The Flutter tester uses this as a signal that a test is still
|
||||||
|
/// running.
|
||||||
|
///
|
||||||
|
/// @return Returns if the shell has an engine and the engine has pending
|
||||||
|
/// microtasks.
|
||||||
|
///
|
||||||
|
bool EngineHasPendingMicrotasks() const;
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
/// @brief Accessor for the disable GPU SyncSwitch.
|
/// @brief Accessor for the disable GPU SyncSwitch.
|
||||||
// |Rasterizer::Delegate|
|
// |Rasterizer::Delegate|
|
||||||
|
@ -267,9 +267,11 @@ class ScriptCompletionTaskObserver {
|
|||||||
public:
|
public:
|
||||||
ScriptCompletionTaskObserver(Shell& shell,
|
ScriptCompletionTaskObserver(Shell& shell,
|
||||||
fml::RefPtr<fml::TaskRunner> main_task_runner,
|
fml::RefPtr<fml::TaskRunner> main_task_runner,
|
||||||
|
fml::RefPtr<fml::TaskRunner> ui_task_runner,
|
||||||
bool run_forever)
|
bool run_forever)
|
||||||
: shell_(shell),
|
: shell_(shell),
|
||||||
main_task_runner_(std::move(main_task_runner)),
|
main_task_runner_(std::move(main_task_runner)),
|
||||||
|
ui_task_runner_(std::move(ui_task_runner)),
|
||||||
run_forever_(run_forever) {}
|
run_forever_(run_forever) {}
|
||||||
|
|
||||||
int GetExitCodeForLastError() const {
|
int GetExitCodeForLastError() const {
|
||||||
@ -283,6 +285,12 @@ class ScriptCompletionTaskObserver {
|
|||||||
// just yet.
|
// just yet.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (shell_.EngineHasPendingMicrotasks()) {
|
||||||
|
// Post an empty task to force a run of the engine task observer that
|
||||||
|
// drains the microtask queue.
|
||||||
|
ui_task_runner_->PostTask([] {});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (run_forever_) {
|
if (run_forever_) {
|
||||||
// We need this script to run forever. We have already recorded the last
|
// We need this script to run forever. We have already recorded the last
|
||||||
@ -302,6 +310,7 @@ class ScriptCompletionTaskObserver {
|
|||||||
private:
|
private:
|
||||||
Shell& shell_;
|
Shell& shell_;
|
||||||
fml::RefPtr<fml::TaskRunner> main_task_runner_;
|
fml::RefPtr<fml::TaskRunner> main_task_runner_;
|
||||||
|
fml::RefPtr<fml::TaskRunner> ui_task_runner_;
|
||||||
bool run_forever_ = false;
|
bool run_forever_ = false;
|
||||||
std::optional<DartErrorCode> last_error_;
|
std::optional<DartErrorCode> last_error_;
|
||||||
bool has_terminated_ = false;
|
bool has_terminated_ = false;
|
||||||
@ -456,6 +465,7 @@ int RunTester(const flutter::Settings& settings,
|
|||||||
*shell, // a valid shell
|
*shell, // a valid shell
|
||||||
fml::MessageLoop::GetCurrent()
|
fml::MessageLoop::GetCurrent()
|
||||||
.GetTaskRunner(), // the message loop to terminate
|
.GetTaskRunner(), // the message loop to terminate
|
||||||
|
ui_task_runner, // runner for Dart microtasks
|
||||||
run_forever // should the exit be ignored
|
run_forever // should the exit be ignored
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user