Skip to content

Commit dd6f46c

Browse files
rmacnak-googlea-siva
authored andcommitted
Make flutter_test on Mac exit on error like Linux and Windows. (flutter#4873)
1 parent a80905b commit dd6f46c

File tree

1 file changed

+80
-1
lines changed

1 file changed

+80
-1
lines changed

shell/platform/darwin/desktop/main_mac.mm

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,69 @@
77
#include <iostream>
88

99
#include "flutter/fml/message_loop.h"
10+
#include "flutter/shell/common/platform_view.h"
1011
#include "flutter/shell/common/shell.h"
1112
#include "flutter/shell/common/switches.h"
1213
#include "flutter/shell/platform/darwin/common/platform_mac.h"
1314
#include "flutter/shell/platform/darwin/desktop/flutter_application.h"
15+
#include "flutter/shell/testing/test_runner.h"
1416
#include "flutter/shell/testing/testing.h"
1517
#include "lib/fxl/command_line.h"
1618
#include "lib/fxl/logging.h"
19+
#include "lib/tonic/dart_microtask_queue.h"
20+
21+
// Exit codes used by the Dart command line tool.
22+
const int kApiErrorExitCode = 253;
23+
const int kCompilationErrorExitCode = 254;
24+
const int kErrorExitCode = 255;
25+
26+
// Checks whether the engine's main Dart isolate has no pending work. If so,
27+
// then exit the given message loop.
28+
class ScriptCompletionTaskObserver : public fml::TaskObserver {
29+
public:
30+
ScriptCompletionTaskObserver(fxl::RefPtr<fxl::TaskRunner> task_runner)
31+
: main_task_runner_(std::move(task_runner)),
32+
prev_live_(false),
33+
last_error_(tonic::kNoError) {}
34+
35+
void DidProcessTask() override {
36+
shell::TestRunner& test_runner = shell::TestRunner::Shared();
37+
shell::Engine& engine = test_runner.platform_view().engine();
38+
39+
if (engine.GetLoadScriptError() != tonic::kNoError) {
40+
last_error_ = engine.GetLoadScriptError();
41+
main_task_runner_->PostTask([]() { fml::MessageLoop::GetCurrent().Terminate(); });
42+
return;
43+
}
44+
45+
bool live = engine.UIIsolateHasLivePorts();
46+
if (prev_live_ && !live) {
47+
last_error_ = engine.GetUIIsolateLastError();
48+
main_task_runner_->PostTask([]() { fml::MessageLoop::GetCurrent().Terminate(); });
49+
}
50+
prev_live_ = live;
51+
}
52+
53+
tonic::DartErrorHandleType last_error() { return last_error_; }
54+
55+
private:
56+
fxl::RefPtr<fxl::TaskRunner> main_task_runner_;
57+
bool prev_live_;
58+
tonic::DartErrorHandleType last_error_;
59+
};
60+
61+
int ConvertErrorTypeToExitCode(tonic::DartErrorHandleType error) {
62+
switch (error) {
63+
case tonic::kCompilationErrorType:
64+
return kCompilationErrorExitCode;
65+
case tonic::kApiErrorType:
66+
return kApiErrorExitCode;
67+
case tonic::kUnknownErrorType:
68+
return kErrorExitCode;
69+
default:
70+
return 0;
71+
}
72+
}
1773

1874
static fxl::CommandLine InitializedCommandLine() {
1975
std::vector<std::string> args_vector;
@@ -47,8 +103,31 @@ int main(int argc, const char* argv[]) {
47103
if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::NonInteractive))) {
48104
if (!shell::InitForTesting(std::move(command_line)))
49105
return 1;
106+
107+
// Note that this task observer must be added after the observer that drains
108+
// the microtask queue.
109+
ScriptCompletionTaskObserver task_observer(fml::MessageLoop::GetCurrent().GetTaskRunner());
110+
blink::Threads::UI()->PostTask(
111+
[&task_observer] { fml::MessageLoop::GetCurrent().AddTaskObserver(&task_observer); });
112+
50113
fml::MessageLoop::GetCurrent().Run();
51-
return EXIT_SUCCESS;
114+
115+
shell::TestRunner& test_runner = shell::TestRunner::Shared();
116+
tonic::DartErrorHandleType error = test_runner.platform_view().engine().GetLoadScriptError();
117+
if (error == tonic::kNoError)
118+
error = task_observer.last_error();
119+
if (error == tonic::kNoError) {
120+
fxl::AutoResetWaitableEvent latch;
121+
blink::Threads::UI()->PostTask([&error, &latch] {
122+
error = tonic::DartMicrotaskQueue::GetForCurrentThread()->GetLastError();
123+
latch.Signal();
124+
});
125+
latch.Wait();
126+
}
127+
128+
// The script has completed and the engine may not be in a clean state,
129+
// so just stop the process.
130+
exit(ConvertErrorTypeToExitCode(error));
52131
} else {
53132
return NSApplicationMain(argc, argv);
54133
}

0 commit comments

Comments
 (0)