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();
|
||||
}
|
||||
|
||||
bool UIDartState::HasPendingMicrotasks() {
|
||||
return microtask_queue_.HasMicrotasks();
|
||||
}
|
||||
|
||||
void UIDartState::AddOrRemoveTaskObserver(bool add) {
|
||||
auto task_runner = context_.task_runners.GetUITaskRunner();
|
||||
if (!task_runner) {
|
||||
|
@ -130,6 +130,8 @@ class UIDartState : public tonic::DartState {
|
||||
|
||||
void FlushMicrotasksNow();
|
||||
|
||||
bool HasPendingMicrotasks();
|
||||
|
||||
fml::WeakPtr<IOManager> GetIOManager() const;
|
||||
|
||||
fml::RefPtr<flutter::SkiaUnrefQueue> GetSkiaUnrefQueue() const;
|
||||
|
@ -511,6 +511,14 @@ bool RuntimeController::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() {
|
||||
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
|
||||
return root_isolate ? root_isolate->GetLastError() : tonic::kNoError;
|
||||
|
@ -523,6 +523,15 @@ class RuntimeController : public PlatformConfigurationClient,
|
||||
///
|
||||
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.
|
||||
///
|
||||
|
@ -293,6 +293,10 @@ bool Engine::UIIsolateHasLivePorts() {
|
||||
return runtime_controller_->HasLivePorts();
|
||||
}
|
||||
|
||||
bool Engine::UIIsolateHasPendingMicrotasks() {
|
||||
return runtime_controller_->HasPendingMicrotasks();
|
||||
}
|
||||
|
||||
tonic::DartErrorHandleType Engine::GetUIIsolateLastError() {
|
||||
return runtime_controller_->GetLastError();
|
||||
}
|
||||
|
@ -682,6 +682,15 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
|
||||
///
|
||||
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
|
||||
/// for further inspection till the next unhandled error comes
|
||||
|
@ -710,6 +710,17 @@ bool Shell::EngineHasLivePorts() const {
|
||||
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 {
|
||||
return is_set_up_;
|
||||
}
|
||||
|
@ -358,6 +358,17 @@ class Shell final : public PlatformView::Delegate,
|
||||
///
|
||||
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.
|
||||
// |Rasterizer::Delegate|
|
||||
|
@ -267,9 +267,11 @@ class ScriptCompletionTaskObserver {
|
||||
public:
|
||||
ScriptCompletionTaskObserver(Shell& shell,
|
||||
fml::RefPtr<fml::TaskRunner> main_task_runner,
|
||||
fml::RefPtr<fml::TaskRunner> ui_task_runner,
|
||||
bool run_forever)
|
||||
: shell_(shell),
|
||||
main_task_runner_(std::move(main_task_runner)),
|
||||
ui_task_runner_(std::move(ui_task_runner)),
|
||||
run_forever_(run_forever) {}
|
||||
|
||||
int GetExitCodeForLastError() const {
|
||||
@ -283,6 +285,12 @@ class ScriptCompletionTaskObserver {
|
||||
// just yet.
|
||||
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_) {
|
||||
// We need this script to run forever. We have already recorded the last
|
||||
@ -302,6 +310,7 @@ class ScriptCompletionTaskObserver {
|
||||
private:
|
||||
Shell& shell_;
|
||||
fml::RefPtr<fml::TaskRunner> main_task_runner_;
|
||||
fml::RefPtr<fml::TaskRunner> ui_task_runner_;
|
||||
bool run_forever_ = false;
|
||||
std::optional<DartErrorCode> last_error_;
|
||||
bool has_terminated_ = false;
|
||||
@ -456,6 +465,7 @@ int RunTester(const flutter::Settings& settings,
|
||||
*shell, // a valid shell
|
||||
fml::MessageLoop::GetCurrent()
|
||||
.GetTaskRunner(), // the message loop to terminate
|
||||
ui_task_runner, // runner for Dart microtasks
|
||||
run_forever // should the exit be ignored
|
||||
);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user