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_TEST_SCOPED_RUN_LOOP_TIMEOUT_H_ 6 #define BASE_TEST_SCOPED_RUN_LOOP_TIMEOUT_H_ 7 8 #include <optional> 9 #include <string> 10 11 #include "base/functional/callback.h" 12 #include "base/gtest_prod_util.h" 13 #include "base/location.h" 14 #include "base/memory/raw_ptr.h" 15 #include "base/run_loop.h" 16 #include "base/time/time.h" 17 18 namespace content { 19 FORWARD_DECLARE_TEST(ContentBrowserTest, RunTimeoutInstalled); 20 } 21 22 namespace base::test { 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: 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 76 ScopedRunLoopTimeout(const Location& timeout_enabled_from_here, 77 TimeDelta timeout); 78 ~ScopedRunLoopTimeout(); 79 80 // Invokes |on_timeout_log| if |timeout| expires, and appends it to the 81 // logged error message. If `timeout` is not specified the current timeout is 82 // used and only the log message is overridden. 83 ScopedRunLoopTimeout(const Location& timeout_enabled_from_here, 84 std::optional<TimeDelta> timeout, 85 RepeatingCallback<std::string()> on_timeout_log); 86 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 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. 103 static void SetAddGTestFailureOnTimeout(); 104 105 // Add provided callback as timeout handler. 106 static void SetTimeoutCallbackForTesting(std::unique_ptr<TimeoutCallback> cb); 107 108 private: 109 TimeoutCallback GetTimeoutCallback(); 110 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 120 raw_ptr<const RunLoop::RunLoopTimeout> const nested_timeout_; 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: 134 const raw_ptr<const RunLoop::RunLoopTimeout> nested_timeout_; 135 }; 136 137 } // namespace base::test 138 139 #endif // BASE_TEST_SCOPED_RUN_LOOP_TIMEOUT_H_ 140