Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2019 The Chromium Authors |
Wez | 9d5dd28 | 2020-02-10 17:21:22 | [diff] [blame] | 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_TEST_SCOPED_RUN_LOOP_TIMEOUT_H_ |
| 6 | #define BASE_TEST_SCOPED_RUN_LOOP_TIMEOUT_H_ |
| 7 | |
Arthur Sonzogni | e5fff99c | 2024-02-21 15:58:24 | [diff] [blame] | 8 | #include <optional> |
Wez | 362b6ca | 2020-02-19 17:17:06 | [diff] [blame] | 9 | #include <string> |
| 10 | |
Avi Drissman | 63e1f99 | 2023-01-13 18:54:43 | [diff] [blame] | 11 | #include "base/functional/callback.h" |
kenkangxgwe | a7eea82 | 2021-08-17 03:21:24 | [diff] [blame] | 12 | #include "base/gtest_prod_util.h" |
Wez | a3ec3fe | 2020-02-17 12:52:16 | [diff] [blame] | 13 | #include "base/location.h" |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 14 | #include "base/memory/raw_ptr.h" |
Wez | 9d5dd28 | 2020-02-10 17:21:22 | [diff] [blame] | 15 | #include "base/run_loop.h" |
| 16 | #include "base/time/time.h" |
| 17 | |
| 18 | namespace content { |
| 19 | FORWARD_DECLARE_TEST(ContentBrowserTest, RunTimeoutInstalled); |
| 20 | } |
| 21 | |
Dana Fried | 0ff12a1 | 2023-06-09 16:51:00 | [diff] [blame] | 22 | namespace base::test { |
Wez | 9d5dd28 | 2020-02-10 17:21:22 | [diff] [blame] | 23 | |
| 24 | FORWARD_DECLARE_TEST(TaskEnvironmentTest, SetsDefaultRunTimeout); |
| 25 | |
| 26 | // Configures all RunLoop::Run() calls on the current thread to run the |
| 27 | // supplied |on_timeout| callback if they run for longer than |timeout|. |
| 28 | // |
| 29 | // Specifying Run() timeouts per-thread avoids the need to cope with Run()s |
| 30 | // executing concurrently with ScopedRunLoopTimeout initialization or |
| 31 | // teardown, and allows "default" timeouts to be specified by suites, rather |
| 32 | // than explicitly configuring them for every RunLoop, in each test. |
| 33 | // |
| 34 | // This is used by test classes including TaskEnvironment and TestSuite to |
| 35 | // set a default Run() timeout on the main thread of all tests which use them. |
| 36 | // |
| 37 | // Tests which have steps which need to Run() for longer than their suite's |
| 38 | // default (if any) allows can override the active timeout by creating a nested |
| 39 | // ScopedRunLoopTimeout on their stack, e.g: |
| 40 | // |
| 41 | // ScopedRunLoopTimeout default_timeout(kDefaultRunTimeout); |
| 42 | // ... do other test stuff ... |
| 43 | // RunLoop().Run(); // Run for up to kDefaultRunTimeout. |
| 44 | // ... |
| 45 | // { |
| 46 | // ScopedRunLoopTimeout specific_timeout(kTestSpecificTimeout); |
| 47 | // RunLoop().Run(); // Run for up to kTestSpecificTimeout. |
| 48 | // } |
| 49 | // ... |
| 50 | // RunLoop().Run(); // Run for up to kDefaultRunTimeout. |
| 51 | // |
| 52 | // The currently-active timeout can also be temporarily disabled: |
| 53 | // ScopedDisableRunLoopTimeout disable_timeout; |
| 54 | // |
| 55 | // By default LOG(FATAL) will be invoked on Run() timeout. Test binaries |
| 56 | // can opt-in to using ADD_FAILURE() instead by calling |
| 57 | // SetAddGTestFailureOnTimeout() during process initialization. |
| 58 | // |
| 59 | // TaskEnvironment applies a default Run() timeout. |
| 60 | |
| 61 | class ScopedRunLoopTimeout { |
| 62 | public: |
Paul Semel | 1aba415 | 2023-09-28 16:46:13 | [diff] [blame] | 63 | // This callback is the one called upon run loop timeouts. |
| 64 | // RunLoop inner mechanism will call this callback after having quit the run |
| 65 | // loop. Implementer might chose to log locations, crash the process, dump a |
| 66 | // stack trace, depending on the desired behaviour for run loop timeouts. |
| 67 | // Invoking `on_timeout_log` might return a personalized timeouts message |
| 68 | // string. This callback was sent at ScopedRunLoopTimeout creation. Invoking |
| 69 | // this callback is not mandatory, as it depends on the desired behaviour of |
| 70 | // this function. |
| 71 | using TimeoutCallback = base::RepeatingCallback<void( |
| 72 | const Location& timeout_enabled_from_here, |
| 73 | RepeatingCallback<std::string()> on_timeout_log, |
| 74 | const Location& run_from_here)>; |
| 75 | |
danakj | e125e8d6 | 2021-01-21 22:06:31 | [diff] [blame] | 76 | ScopedRunLoopTimeout(const Location& timeout_enabled_from_here, |
| 77 | TimeDelta timeout); |
Wez | 9d5dd28 | 2020-02-10 17:21:22 | [diff] [blame] | 78 | ~ScopedRunLoopTimeout(); |
| 79 | |
Wez | 362b6ca | 2020-02-19 17:17:06 | [diff] [blame] | 80 | // Invokes |on_timeout_log| if |timeout| expires, and appends it to the |
Dana Fried | 0ff12a1 | 2023-06-09 16:51:00 | [diff] [blame] | 81 | // logged error message. If `timeout` is not specified the current timeout is |
| 82 | // used and only the log message is overridden. |
danakj | e125e8d6 | 2021-01-21 22:06:31 | [diff] [blame] | 83 | ScopedRunLoopTimeout(const Location& timeout_enabled_from_here, |
Arthur Sonzogni | e5fff99c | 2024-02-21 15:58:24 | [diff] [blame] | 84 | std::optional<TimeDelta> timeout, |
Wez | 362b6ca | 2020-02-19 17:17:06 | [diff] [blame] | 85 | RepeatingCallback<std::string()> on_timeout_log); |
| 86 | |
Wez | 9d5dd28 | 2020-02-10 17:21:22 | [diff] [blame] | 87 | ScopedRunLoopTimeout(const ScopedRunLoopTimeout&) = delete; |
| 88 | ScopedRunLoopTimeout& operator=(const ScopedRunLoopTimeout&) = delete; |
| 89 | |
| 90 | // Returns true if there is a Run() timeout configured on the current thread. |
| 91 | static bool ExistsForCurrentThread(); |
| 92 | |
Paul Semel | 1aba415 | 2023-09-28 16:46:13 | [diff] [blame] | 93 | // Important note: |
| 94 | // The two following static methods will alter the behaviour on run loop |
| 95 | // timeouts. If both methods are being called (whatever the ordering), the |
| 96 | // behaviour will be chained, which means that both callbacks will be invoked. |
| 97 | // If the custom callback handling is reset (`SetTimeoutCallbackForTesting` |
| 98 | // called with `nullptr`), then we reset the behaviour to its previous state, |
| 99 | // which is, if `SetAddGTestFailureOnTimeout`, it will invoke GTest timeout |
| 100 | // handling. Otherwise, it will invoke the default function. |
| 101 | |
| 102 | // Add GTest timeout handler. |
Wez | 9d5dd28 | 2020-02-10 17:21:22 | [diff] [blame] | 103 | static void SetAddGTestFailureOnTimeout(); |
| 104 | |
Paul Semel | 1aba415 | 2023-09-28 16:46:13 | [diff] [blame] | 105 | // Add provided callback as timeout handler. |
| 106 | static void SetTimeoutCallbackForTesting(std::unique_ptr<TimeoutCallback> cb); |
| 107 | |
| 108 | private: |
| 109 | TimeoutCallback GetTimeoutCallback(); |
| 110 | |
Wez | 9d5dd28 | 2020-02-10 17:21:22 | [diff] [blame] | 111 | protected: |
| 112 | FRIEND_TEST_ALL_PREFIXES(ScopedRunLoopRunTimeoutTest, TimesOut); |
| 113 | FRIEND_TEST_ALL_PREFIXES(ScopedRunLoopRunTimeoutTest, RunTasksUntilTimeout); |
| 114 | FRIEND_TEST_ALL_PREFIXES(TaskEnvironmentTest, SetsDefaultRunTimeout); |
| 115 | FRIEND_TEST_ALL_PREFIXES(content::ContentBrowserTest, RunTimeoutInstalled); |
| 116 | |
| 117 | // Exposes the RunLoopTimeout to the friend tests (see above). |
| 118 | static const RunLoop::RunLoopTimeout* GetTimeoutForCurrentThread(); |
| 119 | |
Ho Cheung | 478b411 | 2023-05-24 22:01:16 | [diff] [blame] | 120 | raw_ptr<const RunLoop::RunLoopTimeout> const nested_timeout_; |
Wez | 9d5dd28 | 2020-02-10 17:21:22 | [diff] [blame] | 121 | RunLoop::RunLoopTimeout run_timeout_; |
| 122 | }; |
| 123 | |
| 124 | class ScopedDisableRunLoopTimeout { |
| 125 | public: |
| 126 | ScopedDisableRunLoopTimeout(); |
| 127 | ~ScopedDisableRunLoopTimeout(); |
| 128 | |
| 129 | ScopedDisableRunLoopTimeout(const ScopedDisableRunLoopTimeout&) = delete; |
| 130 | ScopedDisableRunLoopTimeout& operator=(const ScopedDisableRunLoopTimeout&) = |
| 131 | delete; |
| 132 | |
| 133 | private: |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 134 | const raw_ptr<const RunLoop::RunLoopTimeout> nested_timeout_; |
Wez | 9d5dd28 | 2020-02-10 17:21:22 | [diff] [blame] | 135 | }; |
| 136 | |
Dana Fried | 0ff12a1 | 2023-06-09 16:51:00 | [diff] [blame] | 137 | } // namespace base::test |
Wez | 9d5dd28 | 2020-02-10 17:21:22 | [diff] [blame] | 138 | |
| 139 | #endif // BASE_TEST_SCOPED_RUN_LOOP_TIMEOUT_H_ |