• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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