xref: /aosp_15_r20/external/cronet/base/task/sequence_manager/work_tracker_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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