Mir

Merge lp:~afrantzis/mir/fix-surface-visibility-event-test into lp:mir

Proposed by Alexandros Frantzis
Status: Merged
Approved by: Andreas Pokorny
Approved revision: no longer in the source branch.
Merged at revision: 3550
Proposed branch: lp:~afrantzis/mir/fix-surface-visibility-event-test
Merge into: lp:mir
Diff against target: 130 lines (+25/-9)
3 files modified
src/include/server/mir/shell/canonical_window_manager.h (+3/-1)
src/server/shell/canonical_window_manager.cpp (+2/-0)
tests/acceptance-tests/test_client_surface_visibility.cpp (+20/-8)
To merge this branch: bzr merge lp:~afrantzis/mir/fix-surface-visibility-event-test
Reviewer Review Type Date Requested Status
Andreas Pokorny (community) Approve
Cemil Azizoglu (community) Approve
Mir CI Bot continuous-integration Approve
Review via email: mp+298135@code.launchpad.net

Commit message

tests: Fix race conditions affecting MirSurfaceVisibilityEvent tests

Description of the change

tests: Fix race conditions affecting MirSurfaceVisibilityEvent tests

Three problems/races were identified and fixed:

1. WindowManagerPolicy function calls are normally serialized using locks in BasicWindowManager. However, msh::CanonicalWindowManagerPolicy::select_active_surface() could be called unlocked through SurfaceReadyObserver, leading to various races and subsequent failures. This was fixed by serializing select_active_surface() with an internal (recursive) lock. There are other solutions, which involve changing the API, but I didn't want to interfere with the API without Alan's feedback. This solution is good enough for now.

2. For reasons unknown, googlemock doesn't fully clear the expectations with VerifyAndClearExpectations(), causing intermittent failures for visibility events received during surface teardown. This problem was worked around by unsetting the client surface event handler before surface destruction.

3. Waiting for a surface to become visible is not a sufficient condition for testing that the surface has reached a steady state as needed by the tests. We also need to wait for the surface to get the focus. This MP fixes the problem by waiting for both visibility and focus state when creating a surface. We use a spin_wait instead of monitoring surface events to workaround the same googlemock problem mentioned in (2).

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3549
https://mir-jenkins.ubuntu.com/job/mir-ci/1173/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/1320
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1371
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1362
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1362
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1334
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1334/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1334
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1334/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1334
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1334/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1334
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1334/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1334
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1334/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1173/rebuild

review: Approve (continuous-integration)
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

LGTM

review: Approve
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

lgtm

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/include/server/mir/shell/canonical_window_manager.h'
2--- src/include/server/mir/shell/canonical_window_manager.h 2016-05-03 06:55:25 +0000
3+++ src/include/server/mir/shell/canonical_window_manager.h 2016-06-22 15:26:47 +0000
4@@ -106,7 +106,6 @@
5
6 geometry::Rectangle display_area;
7 geometry::Point old_cursor{};
8- std::weak_ptr<scene::Surface> active_surface_;
9 using FullscreenSurfaces = std::set<std::weak_ptr<scene::Surface>, std::owner_less<std::weak_ptr<scene::Surface>>>;
10
11 FullscreenSurfaces fullscreen_surfaces;
12@@ -114,6 +113,9 @@
13 bool resizing = false;
14 bool left_resize = false;
15 bool top_resize = false;
16+
17+ std::recursive_mutex active_surface_mutex;
18+ std::weak_ptr<scene::Surface> active_surface_;
19 };
20
21 using CanonicalWindowManager = WindowManagerConstructor<CanonicalWindowManagerPolicy>;
22
23=== modified file 'src/server/shell/canonical_window_manager.cpp'
24--- src/server/shell/canonical_window_manager.cpp 2016-06-07 19:23:52 +0000
25+++ src/server/shell/canonical_window_manager.cpp 2016-06-22 15:26:47 +0000
26@@ -757,6 +757,8 @@
27
28 void msh::CanonicalWindowManagerPolicy::select_active_surface(std::shared_ptr<ms::Surface> const& surface)
29 {
30+ std::lock_guard<std::recursive_mutex> lock{active_surface_mutex};
31+
32 if (!surface)
33 {
34 if (active_surface_.lock())
35
36=== modified file 'tests/acceptance-tests/test_client_surface_visibility.cpp'
37--- tests/acceptance-tests/test_client_surface_visibility.cpp 2016-05-03 06:55:25 +0000
38+++ tests/acceptance-tests/test_client_surface_visibility.cpp 2016-06-22 15:26:47 +0000
39@@ -25,6 +25,7 @@
40
41 #include "mir_test_framework/connected_client_with_a_surface.h"
42 #include "mir/test/signal.h"
43+#include "mir/test/spin_wait.h"
44
45 #include <mutex>
46 #include <condition_variable>
47@@ -81,6 +82,10 @@
48 MOCK_METHOD2(handle, void(MirSurface*,MirSurfaceVisibility));
49 };
50
51+void null_event_callback(MirSurface*, MirEvent const*, void*)
52+{
53+}
54+
55 void event_callback(MirSurface* surface, MirEvent const* event, void* ctx)
56 {
57 if (mir_event_get_type(event) != mir_event_type_surface)
58@@ -96,12 +101,12 @@
59 static_cast<MirSurfaceVisibility>(mir_surface_event_get_attribute_value(sev)));
60 }
61
62-MirSurface* create_surface(MirConnection* connection, geom::Size size,
63+MirSurface* create_surface(MirConnection* connection, const char* name, geom::Size size,
64 testing::NiceMock<MockVisibilityCallback>& mock_callback)
65 {
66 auto const spec = mir_connection_create_spec_for_normal_surface(
67 connection, size.width.as_int(), size.height.as_int(), mir_pixel_format_bgr_888);
68- mir_surface_spec_set_name(spec, "ConnectedClientWithASurfaceFixtureSurface");
69+ mir_surface_spec_set_name(spec, name);
70 mir_surface_spec_set_buffer_usage(spec, mir_buffer_usage_hardware);
71 mir_surface_spec_set_event_handler(spec, &event_callback, &mock_callback);
72 auto surface = mir_surface_create_sync(spec);
73@@ -111,14 +116,15 @@
74
75 struct Surface
76 {
77- Surface(MirConnection* connection, geom::Size size) :
78- surface(create_surface(connection, size, callback))
79+ Surface(MirConnection* connection, char const* name, geom::Size size) :
80+ surface(create_surface(connection, name, size, callback))
81 {
82- wait_for_visible();
83+ wait_for_visible_and_focused();
84 }
85
86 ~Surface()
87 {
88+ mir_surface_set_event_handler(surface, null_event_callback, nullptr);
89 mir_surface_release_sync(surface);
90 }
91
92@@ -146,7 +152,7 @@
93 }
94
95 private:
96- void wait_for_visible()
97+ void wait_for_visible_and_focused()
98 {
99 expect_surface_visibility_event_after(
100 mir_surface_visibility_exposed,
101@@ -154,6 +160,12 @@
102 {
103 mir_buffer_stream_swap_buffers_sync(mir_surface_get_buffer_stream(surface));
104 });
105+
106+ // GMock is behaving strangely, checking expectations after they
107+ // have been cleared, so we use spin_wait() instead.
108+ mt::spin_wait_for_condition_or_timeout(
109+ [this] { return mir_surface_get_focus(surface) == mir_surface_focused; },
110+ std::chrono::seconds{2});
111 }
112
113 testing::NiceMock<MockVisibilityCallback> callback;
114@@ -172,7 +184,7 @@
115 });
116
117 mtf::ConnectedClientHeadlessServer::SetUp();
118- surface = std::make_unique<Surface>(connection, small_size);
119+ surface = std::make_unique<Surface>(connection, "small", small_size);
120 }
121
122 void TearDown() override
123@@ -184,7 +196,7 @@
124
125 void create_larger_surface_on_top()
126 {
127- second_surface = std::make_unique<Surface>(connection, large_size);
128+ second_surface = std::make_unique<Surface>(connection, "large", large_size);
129 shell.lock()->raise(1);
130 }
131

Subscribers

People subscribed via source and target branches