New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added unit tests to the engine. #20216
Conversation
8777c4b
to
11f3f21
Compare
11f3f21
to
6a0d3a4
Compare
shell/common/engine.h
Outdated
/// `DispatchPlatformMessage` unless you are writing tests. | ||
/// | ||
template <typename RuntimeControllerProxy> | ||
void DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might not scale well in the future, we'll see. It was this or make RuntimeController not final and give it virtual methods, which would have runtime costs. RuntimeController
is very complicated to use in tests since it requires a dart snapshot and everything that goes along with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also worth noting, I tried to make this method private but that doesn't scale well since googletest compiles each test as its own class that has to be friended. I can still do that if you want. It's not breaking any encapsulation having it public, it is a bit cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This OOLs a bunch of code and I agree with your hunch that this won't scale well. If the behavior of a the component is hard to test without templating, visibility or const correctness hacks, it usually means that that it has more than a single responsibility. That seems to be the case here.
Instead, I suggest isolating the message dispatcher into its own component (something like PlatformMessageDispatcher
) and testing that separately from the engine. Then engine can then use an instance of this tested component. The implementation of this new object would just be a proc lookup in a map keyed by the channel name which is pretty much what is happening here. The test assertions can check the correctness of the entries in this map. For this, you don't need any of the Dart VM bits at all.
Thanks @chinmaygarde That approach has scaling issues as well. Right now |
Trying to avoid a virtual function call per platform message dispatch sounds like it might be premature optimization to me. Are there statistics that show that these messages come in at high enough volume to measure these nanoseconds? |
@flar It's an optimization, I wouldn't call it premature though. This is engine code in the place where messages are getting dispatched which can get some heavy usage. Virtual functions add just a couple of cycles to calls but more importantly they block optimizations like inlining. In isolation they don't matter much, but in aggregate across something like the engine it can make a big difference. I'm fine making the methods virtual. I didn't think this was that bad of a tradeoff to get testability with no performance cost though. As we add more tests I'm skeptical this will last though and we'll probably have to migrate to virtual methods anyway. |
shell/common/engine_unittests.cc
Outdated
class MockRuntimeDelegate : public RuntimeDelegate { | ||
public: | ||
MOCK_METHOD(std::string, DefaultRouteName, (), (override)); | ||
MOCK_METHOD(void, ScheduleFrame, (bool), (override)); | ||
MOCK_METHOD(void, Render, (std::unique_ptr<flutter::LayerTree>), (override)); | ||
MOCK_METHOD(void, | ||
UpdateSemantics, | ||
(SemanticsNodeUpdates, CustomAccessibilityActionUpdates), | ||
(override)); | ||
MOCK_METHOD(void, | ||
HandlePlatformMessage, | ||
(fml::RefPtr<PlatformMessage>), | ||
(override)); | ||
MOCK_METHOD(FontCollection&, GetFontCollection, (), (override)); | ||
MOCK_METHOD(void, | ||
UpdateIsolateDescription, | ||
(const std::string, int64_t), | ||
(override)); | ||
MOCK_METHOD(void, SetNeedsReportTimings, (bool), (override)); | ||
|
||
MOCK_METHOD(std::unique_ptr<std::vector<std::string>>, | ||
ComputePlatformResolvedLocale, | ||
(const std::vector<std::string>&), | ||
(override)); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could get rid of the need for this if we were willing to change the RuntimeControllers instance variable for its RuntimeDelegate from a reference to a pointer. I think thats a desirable change but I suspected it might be controversial.
@chinmaygarde @flar I moved to virtual methods in the RuntimeController =) |
75dddd2
to
45dcf58
Compare
One sec, I'm still battling a bug in googletest on windows. I think if i used the deprecated methods MOCK_METHOD0 versus MOCK_METHOD it should work. |
775b93a
to
31be985
Compare
My "food for thought" comment above was the extent of my review, so consider the matter resolved if you took it under consideration and came up with an acceptable solution... |
Landing before last CI test passes. This last test previously passed, the only change since then should be covered in other tests. When the test first ran it had an infra error. When it was rerun it got queued for over 2 hours. Attempts to launch it manually with $ led get-builder 'luci.flutter.try:Mac Host Engine'
E0807 15:52:40.850576 74654 fleetspeak.go:79] Error flushing fleetspeak data: (downstream) write of 13191 bytes (compressed payload) + metadata: Dial("/var/run/fleetspeak/clp_exporter.sock", "CL:324807037"): dial unix /var/run/fleetspeak/clp_exporter.sock: connect: permission denied
E0807 15:53:40.732003 74654 fleetspeak.go:79] Error flushing fleetspeak data: previous message still pending send: (downstream) write of 13191 bytes (compressed payload) + metadata: Dial("/var/run/fleetspeak/clp_exporter.sock", "CL:324807037"): dial unix /var/run/fleetspeak/clp_exporter.sock: connect: permission denied |
Description
Added tests to the Engine, previously there were none. The tests that were added were for the benefit of #20193
In order to make messages testable without incurring a performance cost I had to factor out one method to be templated so that we can delegate RuntimeController methods elsewhere.
Related Issues
#20193
Tests
EngineTest
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]
). This will ensure a smooth and quick review process.Breaking Change
Did any tests fail when you ran them? Please read handling breaking changes.