xref: /aosp_15_r20/external/cronet/base/task/thread_pool/can_run_policy_test.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 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 #ifndef BASE_TASK_THREAD_POOL_CAN_RUN_POLICY_TEST_H_
6 #define BASE_TASK_THREAD_POOL_CAN_RUN_POLICY_TEST_H_
7 
8 #include "base/synchronization/atomic_flag.h"
9 #include "base/task/task_runner.h"
10 #include "base/task/thread_pool/task_tracker.h"
11 #include "base/task/thread_pool/test_utils.h"
12 #include "base/test/bind.h"
13 #include "base/test/test_timeouts.h"
14 #include "base/test/test_waitable_event.h"
15 #include "base/threading/platform_thread.h"
16 #include "build/build_config.h"
17 
18 namespace base {
19 namespace internal {
20 namespace test {
21 
22 // Verify that tasks only run when allowed by the CanRunPolicy. |target| is the
23 // object on which DidUpdateCanRunPolicy() must be called after updating the
24 // CanRunPolicy in |task_tracker|. |create_task_runner| is a function that
25 // receives a TaskPriority and returns a TaskRunner. |task_tracker| is the
26 // TaskTracker.
27 template <typename Target, typename CreateTaskRunner>
TestCanRunPolicyBasic(Target * target,CreateTaskRunner create_task_runner,TaskTracker * task_tracker)28 void TestCanRunPolicyBasic(Target* target,
29                            CreateTaskRunner create_task_runner,
30                            TaskTracker* task_tracker) {
31   AtomicFlag foreground_can_run;
32   TestWaitableEvent foreground_did_run;
33   AtomicFlag best_effort_can_run;
34   TestWaitableEvent best_effort_did_run;
35 
36   task_tracker->SetCanRunPolicy(CanRunPolicy::kNone);
37   target->DidUpdateCanRunPolicy();
38 
39   const auto user_visible_task_runner =
40       create_task_runner(TaskPriority::USER_VISIBLE);
41   user_visible_task_runner->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
42                                        EXPECT_TRUE(foreground_can_run.IsSet());
43                                        foreground_did_run.Signal();
44                                      }));
45   const auto best_effort_task_runner =
46       create_task_runner(TaskPriority::BEST_EFFORT);
47   best_effort_task_runner->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
48                                       EXPECT_TRUE(best_effort_can_run.IsSet());
49                                       best_effort_did_run.Signal();
50                                     }));
51 
52   PlatformThread::Sleep(TestTimeouts::tiny_timeout());
53 
54   foreground_can_run.Set();
55   task_tracker->SetCanRunPolicy(CanRunPolicy::kForegroundOnly);
56   target->DidUpdateCanRunPolicy();
57   foreground_did_run.Wait();
58 
59   PlatformThread::Sleep(TestTimeouts::tiny_timeout());
60 
61   best_effort_can_run.Set();
62   task_tracker->SetCanRunPolicy(CanRunPolicy::kAll);
63   target->DidUpdateCanRunPolicy();
64   best_effort_did_run.Wait();
65 }
66 
67 // Verify that if a task was allowed to run by the CanRunPolicy when it was
68 // posted, but the CanRunPolicy is updated to disallow it from running before it
69 // starts running, it doesn't run. |target| is the object on which
70 // DidUpdateCanRunPolicy() must be called after updating the CanRunPolicy in
71 // |task_tracker|. |create_task_runner| is a function that receives a
72 // TaskPriority and returns a *Sequenced*TaskRunner. |task_tracker| is the
73 // TaskTracker.
74 template <typename Target, typename CreateTaskRunner>
TestCanRunPolicyChangedBeforeRun(Target * target,CreateTaskRunner create_task_runner,TaskTracker * task_tracker)75 void TestCanRunPolicyChangedBeforeRun(Target* target,
76                                       CreateTaskRunner create_task_runner,
77                                       TaskTracker* task_tracker) {
78   constexpr struct {
79     // Descriptor for the test case.
80     const char* descriptor;
81     // Task priority being tested.
82     TaskPriority priority;
83     // Policy that disallows running tasks with |priority|.
84     CanRunPolicy disallow_policy;
85     // Policy that allows running tasks with |priority|.
86     CanRunPolicy allow_policy;
87   } kTestCases[] = {
88       {"BestEffort/kNone/kAll", TaskPriority::BEST_EFFORT, CanRunPolicy::kNone,
89        CanRunPolicy::kAll},
90       {"BestEffort/kForegroundOnly/kAll", TaskPriority::BEST_EFFORT,
91        CanRunPolicy::kForegroundOnly, CanRunPolicy::kAll},
92       {"UserVisible/kNone/kForegroundOnly", TaskPriority::USER_VISIBLE,
93        CanRunPolicy::kNone, CanRunPolicy::kForegroundOnly},
94       {"UserVisible/kNone/kAll", TaskPriority::USER_VISIBLE,
95        CanRunPolicy::kNone, CanRunPolicy::kAll}};
96 
97   for (auto& test_case : kTestCases) {
98     SCOPED_TRACE(test_case.descriptor);
99 
100     TestWaitableEvent first_task_started;
101     TestWaitableEvent first_task_blocked;
102     AtomicFlag second_task_can_run;
103 
104     task_tracker->SetCanRunPolicy(test_case.allow_policy);
105     target->DidUpdateCanRunPolicy();
106 
107     const auto task_runner = create_task_runner(test_case.priority);
108     task_runner->PostTask(
109         FROM_HERE, BindLambdaForTesting([&]() {
110           first_task_started.Signal();
111           first_task_blocked.Wait();
112         }));
113     task_runner->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
114                             EXPECT_TRUE(second_task_can_run.IsSet());
115                           }));
116 
117     first_task_started.Wait();
118     task_tracker->SetCanRunPolicy(test_case.disallow_policy);
119     target->DidUpdateCanRunPolicy();
120     first_task_blocked.Signal();
121 
122     PlatformThread::Sleep(TestTimeouts::tiny_timeout());
123 
124     second_task_can_run.Set();
125     task_tracker->SetCanRunPolicy(test_case.allow_policy);
126     target->DidUpdateCanRunPolicy();
127     task_tracker->FlushForTesting();
128   }
129 }
130 
131 // Regression test for https://crbug.com/950383
132 template <typename Target, typename CreateTaskRunner>
TestCanRunPolicyLoad(Target * target,CreateTaskRunner create_task_runner,TaskTracker * task_tracker)133 void TestCanRunPolicyLoad(Target* target,
134                           CreateTaskRunner create_task_runner,
135                           TaskTracker* task_tracker) {
136   constexpr struct {
137     // Descriptor for the test case.
138     const char* descriptor;
139     // Task priority being tested.
140     TaskPriority priority;
141     // Policy that allows running tasks with |priority|.
142     CanRunPolicy allow_policy;
143     // Policy that disallows running tasks with |priority|.
144     CanRunPolicy disallow_policy;
145   } kTestCases[] = {
146       {"BestEffort/kAll/kNone", TaskPriority::BEST_EFFORT, CanRunPolicy::kAll,
147        CanRunPolicy::kNone},
148       {"BestEffort/kAll/kForegroundOnly", TaskPriority::BEST_EFFORT,
149        CanRunPolicy::kAll, CanRunPolicy::kForegroundOnly},
150       {"UserVisible/kForegroundOnly/kNone", TaskPriority::USER_VISIBLE,
151        CanRunPolicy::kForegroundOnly, CanRunPolicy::kNone},
152       {"UserVisible/kAll/kNone", TaskPriority::USER_VISIBLE, CanRunPolicy::kAll,
153        CanRunPolicy::kNone}};
154 
155   for (auto& test_case : kTestCases) {
156     SCOPED_TRACE(test_case.descriptor);
157 
158     task_tracker->SetCanRunPolicy(test_case.allow_policy);
159     target->DidUpdateCanRunPolicy();
160 
161     const auto task_runner = create_task_runner(test_case.priority);
162 
163     // Post less tasks on iOS to avoid timeouts.
164     const size_t kLargeNumber =
165 #if BUILDFLAG(IS_IOS)
166         16;
167 #else
168         256;
169 #endif
170     for (size_t i = 0; i < kLargeNumber; ++i)
171       task_runner->PostTask(FROM_HERE, DoNothing());
172 
173     // Change the CanRunPolicy concurrently with running tasks.
174     // This should not cause crashes.
175     for (size_t i = 0; i < kLargeNumber; ++i) {
176       task_tracker->SetCanRunPolicy(test_case.disallow_policy);
177       target->DidUpdateCanRunPolicy();
178 
179       task_tracker->SetCanRunPolicy(test_case.allow_policy);
180       target->DidUpdateCanRunPolicy();
181     }
182 
183     task_tracker->FlushForTesting();
184   }
185 }
186 
187 }  // namespace test
188 }  // namespace internal
189 }  // namespace base
190 
191 #endif  // BASE_TASK_THREAD_POOL_CAN_RUN_POLICY_TEST_H_
192