1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/task/sequence_manager/work_tracker.h"
6
7 #include <optional>
8
9 #include "base/test/bind.h"
10 #include "base/test/test_timeouts.h"
11 #include "base/threading/platform_thread.h"
12 #include "base/threading/thread.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace base::sequence_manager::internal {
16
17 // Verify that no sync work authorization is granted unless allowed by
18 // `SetRunTaskSynchronouslyAllowed()`.
TEST(SequenceManagerWorkTrackerTest,SetRunTaskSynchronouslyAllowed)19 TEST(SequenceManagerWorkTrackerTest, SetRunTaskSynchronouslyAllowed) {
20 WorkTracker tracker;
21 EXPECT_FALSE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
22
23 tracker.OnBeginWork();
24 tracker.OnIdle();
25 EXPECT_FALSE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
26
27 tracker.WillRequestReloadImmediateWorkQueue();
28 tracker.WillReloadImmediateWorkQueues();
29 tracker.OnIdle();
30 EXPECT_FALSE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
31
32 tracker.SetRunTaskSynchronouslyAllowed(true);
33 EXPECT_TRUE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
34 tracker.SetRunTaskSynchronouslyAllowed(false);
35 EXPECT_FALSE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
36 }
37
38 // Verify that `SetRunTaskSynchronouslyAllowed(false)` blocks until there is no
39 // valid sync work authorization.
TEST(SequenceManagerWorkTrackerTest,SetRunTaskSynchronouslyAllowedBlocks)40 TEST(SequenceManagerWorkTrackerTest, SetRunTaskSynchronouslyAllowedBlocks) {
41 WorkTracker tracker;
42 tracker.SetRunTaskSynchronouslyAllowed(true);
43
44 WaitableEvent did_acquire_sync_work_auth;
45 bool will_release_sync_work_auth = false;
46 Thread other_thread("OtherThread");
47 other_thread.Start();
48 other_thread.task_runner()->PostTask(
49 FROM_HERE, BindLambdaForTesting([&]() {
50 std::optional<SyncWorkAuthorization> auth =
51 tracker.TryAcquireSyncWorkAuthorization();
52 EXPECT_TRUE(auth->IsValid());
53 did_acquire_sync_work_auth.Signal();
54 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
55 will_release_sync_work_auth = true;
56 auth.reset();
57 }));
58
59 did_acquire_sync_work_auth.Wait();
60
61 tracker.SetRunTaskSynchronouslyAllowed(false);
62 // `will_release_sync_work_auth` must be true (with no data race detected by
63 // TSAN) when the call above returns.
64 EXPECT_TRUE(will_release_sync_work_auth);
65
66 other_thread.FlushForTesting();
67 }
68
69 // Verify that after `WillRequestReloadImmediateWorkQueue()`,
70 // `WillReloadImmediateWorkQueues()` and `OnIdle()` must be called in sequence
71 // for a sync work authorization to be granted.
TEST(SequenceManagerWorkTrackerTest,WillRequestReloadImmediateWorkQueue)72 TEST(SequenceManagerWorkTrackerTest, WillRequestReloadImmediateWorkQueue) {
73 WorkTracker tracker;
74 tracker.SetRunTaskSynchronouslyAllowed(true);
75 EXPECT_TRUE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
76
77 tracker.WillRequestReloadImmediateWorkQueue();
78 EXPECT_FALSE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
79 tracker.WillReloadImmediateWorkQueues();
80 EXPECT_FALSE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
81 tracker.OnIdle();
82 EXPECT_TRUE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
83
84 tracker.WillRequestReloadImmediateWorkQueue();
85 EXPECT_FALSE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
86 // `OnIdle()` without `WillReloadImmediateWorkQueues()` is not sufficient for
87 // a sync work authorization to be granted.
88 tracker.OnIdle();
89 EXPECT_FALSE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
90 }
91
92 // Verify that after `OnBeginWork()`, `OnIdle()` must be called for a sync
93 // work authorization to be granted.
TEST(SequenceManagerWorkTrackerTest,OnBeginWork)94 TEST(SequenceManagerWorkTrackerTest, OnBeginWork) {
95 WorkTracker tracker;
96 tracker.SetRunTaskSynchronouslyAllowed(true);
97 EXPECT_TRUE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
98
99 tracker.OnBeginWork();
100 EXPECT_FALSE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
101 tracker.OnIdle();
102 EXPECT_TRUE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
103 }
104
105 // Verify that its not possible to simultaneously acquire two sync work
106 // authorizations.
TEST(SequenceManagerWorkTrackerTest,TwoSyncWorkAuthorizations)107 TEST(SequenceManagerWorkTrackerTest, TwoSyncWorkAuthorizations) {
108 WorkTracker tracker;
109 tracker.SetRunTaskSynchronouslyAllowed(true);
110
111 std::optional<SyncWorkAuthorization> first =
112 tracker.TryAcquireSyncWorkAuthorization();
113 EXPECT_TRUE(first->IsValid());
114 SyncWorkAuthorization second = tracker.TryAcquireSyncWorkAuthorization();
115 EXPECT_FALSE(second.IsValid());
116
117 first.reset();
118 // `second` is invalid so doesn't prevent acquiring another sync work
119 // authorization.
120 EXPECT_TRUE(tracker.TryAcquireSyncWorkAuthorization().IsValid());
121 }
122
123 // Verify that `OnBeginWork()` blocks until there is no valid sync work
124 // authorization.
TEST(SequenceManagerWorkTrackerTest,OnBeginWorkBlocks)125 TEST(SequenceManagerWorkTrackerTest, OnBeginWorkBlocks) {
126 WorkTracker tracker;
127 tracker.SetRunTaskSynchronouslyAllowed(true);
128
129 WaitableEvent did_acquire_sync_work_auth;
130 bool will_release_sync_work_auth = false;
131 Thread other_thread("OtherThread");
132 other_thread.Start();
133 other_thread.task_runner()->PostTask(
134 FROM_HERE, BindLambdaForTesting([&]() {
135 std::optional<SyncWorkAuthorization> auth =
136 tracker.TryAcquireSyncWorkAuthorization();
137 EXPECT_TRUE(auth->IsValid());
138 did_acquire_sync_work_auth.Signal();
139 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
140 will_release_sync_work_auth = true;
141 auth.reset();
142 }));
143
144 did_acquire_sync_work_auth.Wait();
145
146 tracker.OnBeginWork();
147 // `will_release_sync_work_auth` must be true (with no data race detected by
148 // TSAN) when the call above returns.
149 EXPECT_TRUE(will_release_sync_work_auth);
150
151 other_thread.FlushForTesting();
152 }
153
154 } // namespace base::sequence_manager::internal
155