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/ios/scoped_critical_action.h" 6 7#include <memory> 8 9#include "base/task/thread_pool.h" 10#include "base/test/ios/wait_util.h" 11#include "base/test/scoped_feature_list.h" 12#include "base/test/task_environment.h" 13#include "testing/gtest/include/gtest/gtest.h" 14#include "testing/platform_test.h" 15 16using base::test::ios::kWaitForActionTimeout; 17using base::test::ios::WaitUntilConditionOrTimeout; 18 19namespace base::ios { 20namespace { 21 22class ScopedCriticalActionTest : public PlatformTest { 23 protected: 24 ScopedCriticalActionTest() { 25 ScopedCriticalAction::ClearNumActiveBackgroundTasksForTest(); 26 default_features.InitWithFeatures({kScopedCriticalActionSkipOnShutdown}, 27 {}); 28 } 29 30 ~ScopedCriticalActionTest() override { 31 ScopedCriticalAction::ResetApplicationWillTerminateForTest(); 32 } 33 34 base::test::ScopedFeatureList default_features; 35 36 base::test::TaskEnvironment task_environment_{ 37 base::test::TaskEnvironment::TimeSource::MOCK_TIME}; 38}; 39 40TEST_F(ScopedCriticalActionTest, ShouldStartBackgroundTaskWhenConstructed) { 41 ASSERT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 42 43 ScopedCriticalAction scoped_critical_action("name"); 44 EXPECT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 45} 46 47TEST_F(ScopedCriticalActionTest, ShouldEndBackgroundTaskWhenDestructed) { 48 ScopedCriticalAction::ClearNumActiveBackgroundTasksForTest(); 49 ASSERT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 50 51 auto scoped_critical_action = std::make_unique<ScopedCriticalAction>("name"); 52 ASSERT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 53 54 scoped_critical_action.reset(); 55 EXPECT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 56} 57 58TEST_F(ScopedCriticalActionTest, ShouldUseMultipleBackgroundTasks) { 59 ScopedCriticalAction::ClearNumActiveBackgroundTasksForTest(); 60 ASSERT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 61 62 auto scoped_critical_action1 = 63 std::make_unique<ScopedCriticalAction>("name1"); 64 ASSERT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 65 66 auto scoped_critical_action2 = 67 std::make_unique<ScopedCriticalAction>("name2"); 68 EXPECT_EQ(2, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 69 70 scoped_critical_action1.reset(); 71 EXPECT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 72 73 scoped_critical_action2.reset(); 74 EXPECT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 75} 76 77TEST_F(ScopedCriticalActionTest, ShouldReuseBackgroundTasksForSameName) { 78 ScopedCriticalAction::ClearNumActiveBackgroundTasksForTest(); 79 ASSERT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 80 81 auto scoped_critical_action1 = std::make_unique<ScopedCriticalAction>("name"); 82 ASSERT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 83 84 auto scoped_critical_action2 = std::make_unique<ScopedCriticalAction>("name"); 85 EXPECT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 86 87 scoped_critical_action1.reset(); 88 EXPECT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 89 90 scoped_critical_action2.reset(); 91 EXPECT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 92} 93 94TEST_F(ScopedCriticalActionTest, 95 ShouldNotReuseBackgroundTasksForSameNameIfTimeDifferenceLarge) { 96 ScopedCriticalAction::ClearNumActiveBackgroundTasksForTest(); 97 ASSERT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 98 99 auto scoped_critical_action1 = std::make_unique<ScopedCriticalAction>("name"); 100 ASSERT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 101 102 // Mimic advancing time more than 3 seconds (kMaxTaskReuseDelay). 103 task_environment_.FastForwardBy(base::Seconds(4)); 104 105 auto scoped_critical_action2 = std::make_unique<ScopedCriticalAction>("name"); 106 EXPECT_EQ(2, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 107 108 scoped_critical_action1.reset(); 109 EXPECT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 110 111 scoped_critical_action2.reset(); 112 EXPECT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 113} 114 115TEST_F(ScopedCriticalActionTest, 116 ShouldReuseBackgroundTasksForSameNameIfTimeDifferenceSmall) { 117 ScopedCriticalAction::ClearNumActiveBackgroundTasksForTest(); 118 ASSERT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 119 120 auto scoped_critical_action1 = std::make_unique<ScopedCriticalAction>("name"); 121 ASSERT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 122 123 // Mimic advancing time less than 3 seconds (kMaxTaskReuseDelay). 124 task_environment_.FastForwardBy(base::Seconds(2)); 125 126 auto scoped_critical_action2 = std::make_unique<ScopedCriticalAction>("name"); 127 EXPECT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 128 129 scoped_critical_action1.reset(); 130 EXPECT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 131 132 scoped_critical_action2.reset(); 133 EXPECT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 134} 135 136TEST_F(ScopedCriticalActionTest, ShouldSkipCriticalActionWhenTerminating) { 137 ScopedCriticalAction::ClearNumActiveBackgroundTasksForTest(); 138 ASSERT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 139 140 auto scoped_critical_action1 = std::make_unique<ScopedCriticalAction>("name"); 141 ASSERT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 142 143 ScopedCriticalAction::ApplicationWillTerminate(); 144 145 auto scoped_critical_action2 = 146 std::make_unique<ScopedCriticalAction>("name2"); 147 EXPECT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 148} 149 150TEST_F(ScopedCriticalActionTest, PostTaskSanityTest) { 151 ScopedCriticalAction::ClearNumActiveBackgroundTasksForTest(); 152 ASSERT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 153 154 scoped_refptr<base::SequencedTaskRunner> background_runner( 155 base::ThreadPool::CreateSequencedTaskRunner( 156 {base::MayBlock(), base::TaskPriority::BEST_EFFORT, 157 base::TaskShutdownBehavior::BLOCK_SHUTDOWN})); 158 159 __block bool completed = false; 160 background_runner->PostTask(FROM_HERE, base::BindOnce(^{ 161 completed = true; 162 })); 163 ASSERT_EQ(1, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 164 EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^{ 165 return completed; 166 })); 167 EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^{ 168 return ScopedCriticalAction::GetNumActiveBackgroundTasksForTest() == 0; 169 })); 170 171 ScopedCriticalAction::ApplicationWillTerminate(); 172 completed = false; 173 background_runner->PostTask(FROM_HERE, base::BindOnce(^{ 174 completed = true; 175 })); 176 ASSERT_EQ(0, ScopedCriticalAction::GetNumActiveBackgroundTasksForTest()); 177 EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^{ 178 return completed; 179 })); 180} 181 182} // namespace 183} // namespace base::ios 184