blob: 1a56913feac089b728dc0f3e20365e6f2048c559 [file] [log] [blame]
Etienne Pierre-dorayaec3d572024-10-29 15:13:331// Copyright 2024 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 "content/browser/tracing/background_tracing_rule.h"
6
7#include <memory>
8
9#include "base/base_paths.h"
10#include "base/metrics/histogram_macros_local.h"
11#include "base/path_service.h"
12#include "base/run_loop.h"
13#include "base/system/sys_info.h"
14#include "base/test/bind.h"
15#include "base/test/test_proto_loader.h"
16#include "base/test/test_timeouts.h"
17#include "base/time/time.h"
18#include "base/trace_event/named_trigger.h"
19#include "build/build_config.h"
20#include "content/public/browser/background_tracing_manager.h"
21#include "content/public/test/browser_task_environment.h"
22#include "testing/gtest/include/gtest/gtest.h"
23#include "third_party/perfetto/protos/perfetto/config/chrome/scenario_config.gen.h"
24
25namespace content {
26
27namespace {
28
29base::FilePath GetTestDataRoot() {
30 return base::PathService::CheckedGet(base::DIR_GEN_TEST_DATA_ROOT);
31}
32
33void CreateRuleConfig(const std::string& proto_text,
34 perfetto::protos::gen::TriggerRule& destination) {
35 base::TestProtoLoader loader(GetTestDataRoot().Append(FILE_PATH_LITERAL(
36 "third_party/perfetto/protos/perfetto/"
37 "config/chrome/scenario_config.descriptor")),
38 "perfetto.protos.TriggerRule");
39 std::string serialized_message;
40 loader.ParseFromText(proto_text, serialized_message);
41 ASSERT_TRUE(destination.ParseFromString(serialized_message));
42}
43
44} // namespace
45
46class BackgroundTracingRuleTest : public testing::Test {
47 public:
48 BackgroundTracingRuleTest() = default;
49
50 protected:
51 BrowserTaskEnvironment task_environment_{
52 base::test::TaskEnvironment::TimeSource::MOCK_TIME};
53
Etienne Pierre-doray3dc2c7dc2025-06-12 12:06:3354 content::TracingDelegate tracing_delegate;
Etienne Pierre-dorayaec3d572024-10-29 15:13:3355 std::unique_ptr<content::BackgroundTracingManager>
56 background_tracing_manager =
Etienne Pierre-doray3dc2c7dc2025-06-12 12:06:3357 content::BackgroundTracingManager::CreateInstance(&tracing_delegate);
Etienne Pierre-dorayaec3d572024-10-29 15:13:3358};
59
60TEST_F(BackgroundTracingRuleTest, HistogramRuleFromValidProto) {
61 perfetto::protos::gen::TriggerRule config;
62 CreateRuleConfig(
63 R"pb(
64 name: "test_rule"
65 trigger_chance: 0.5
66 delay_ms: 500
67 histogram: { histogram_name: "foo" min_value: 1 max_value: 2 }
68 )pb",
69 config);
70 auto rule = BackgroundTracingRule::Create(config);
71 auto result = rule->ToProtoForTesting();
72 EXPECT_EQ("test_rule", result.name());
73 EXPECT_EQ(0.5, result.trigger_chance());
74 EXPECT_EQ(500U, result.delay_ms());
75 EXPECT_TRUE(result.has_histogram());
76 EXPECT_EQ("foo", result.histogram().histogram_name());
77 EXPECT_EQ(1, result.histogram().min_value());
78 EXPECT_EQ(2, result.histogram().max_value());
79}
80
81TEST_F(BackgroundTracingRuleTest, HistogramRuleSucceedsOnLowerReferenceValue) {
82 perfetto::protos::gen::TriggerRule config;
83 CreateRuleConfig(
84 R"pb(
85 name: "test_rule"
86 histogram: { histogram_name: "foo" min_value: 1 max_value: 2 }
87 )pb",
88 config);
89 auto rule = BackgroundTracingRule::Create(config);
90 base::RunLoop run_loop;
91 rule->Install(base::BindLambdaForTesting([&](const BackgroundTracingRule*) {
92 run_loop.Quit();
93 return true;
94 }));
95 LOCAL_HISTOGRAM_COUNTS("foo", 1);
96 run_loop.Run();
97 rule->Uninstall();
98}
99
100TEST_F(BackgroundTracingRuleTest, HistogramRuleSucceedsOnUpperReferenceValue) {
101 perfetto::protos::gen::TriggerRule config;
102 CreateRuleConfig(
103 R"pb(
104 name: "test_rule"
105 histogram: { histogram_name: "foo" min_value: 1 max_value: 2 }
106 )pb",
107 config);
108 auto rule = BackgroundTracingRule::Create(config);
109 base::RunLoop run_loop;
110 rule->Install(base::BindLambdaForTesting([&](const BackgroundTracingRule*) {
111 run_loop.Quit();
112 return true;
113 }));
114 LOCAL_HISTOGRAM_COUNTS("foo", 2);
115 run_loop.Run();
116 rule->Uninstall();
117}
118
119TEST_F(BackgroundTracingRuleTest, HistogramRuleSucceedsOnSingleEnumValue) {
120 perfetto::protos::gen::TriggerRule config;
121 CreateRuleConfig(
122 R"pb(
123 name: "test_rule"
124 histogram: { histogram_name: "foo" min_value: 1 max_value: 1 }
125 )pb",
126 config);
127 auto rule = BackgroundTracingRule::Create(config);
128 base::RunLoop run_loop;
129 rule->Install(base::BindLambdaForTesting([&](const BackgroundTracingRule*) {
130 run_loop.Quit();
131 return true;
132 }));
133 LOCAL_HISTOGRAM_COUNTS("foo", 1);
134 run_loop.Run();
135 rule->Uninstall();
136}
137
138TEST_F(BackgroundTracingRuleTest, HistogramRuleFailsOnLowerHistogramSample) {
139 perfetto::protos::gen::TriggerRule config;
140 CreateRuleConfig(
141 R"pb(
142 name: "test_rule"
143 histogram: { histogram_name: "foo" min_value: 1 max_value: 2 }
144 )pb",
145 config);
146 auto rule = BackgroundTracingRule::Create(config);
147 rule->Install(
148 base::BindLambdaForTesting([](const BackgroundTracingRule*) -> bool {
149 ADD_FAILURE();
150 return true;
151 }));
152 LOCAL_HISTOGRAM_COUNTS("foo", 0);
153 task_environment_.FastForwardBy(TestTimeouts::tiny_timeout());
154 rule->Uninstall();
155}
156
157TEST_F(BackgroundTracingRuleTest, HistogramRuleFailsOnHigherHistogramSample) {
158 perfetto::protos::gen::TriggerRule config;
159 CreateRuleConfig(
160 R"pb(
161 name: "test_rule"
162 histogram: { histogram_name: "foo" min_value: 1 max_value: 2 }
163 )pb",
164 config);
165 auto rule = BackgroundTracingRule::Create(config);
166 rule->Install(
167 base::BindLambdaForTesting([](const BackgroundTracingRule*) -> bool {
168 ADD_FAILURE();
169 return true;
170 }));
171 LOCAL_HISTOGRAM_COUNTS("foo", 3);
172 task_environment_.FastForwardBy(TestTimeouts::tiny_timeout());
173 rule->Uninstall();
174}
175
176TEST_F(BackgroundTracingRuleTest, NamedRuleFromValidProto) {
177 perfetto::protos::gen::TriggerRule config;
178 CreateRuleConfig(R"pb(
179 name: "test_rule"
180 trigger_chance: 0.5
181 delay_ms: 500
182 manual_trigger_name: "test_trigger"
183 )pb",
184 config);
185 auto rule = BackgroundTracingRule::Create(config);
186 auto result = rule->ToProtoForTesting();
187 EXPECT_EQ("test_rule", result.name());
188 EXPECT_EQ(0.5, result.trigger_chance());
189 EXPECT_EQ(500U, result.delay_ms());
190 EXPECT_EQ("test_trigger", result.manual_trigger_name());
191}
192
193TEST_F(BackgroundTracingRuleTest, RuleFromEmptyProto) {
194 perfetto::protos::gen::TriggerRule config;
195 CreateRuleConfig(R"pb(
196 name: "test_rule"
197 )pb",
198 config);
199 auto rule = BackgroundTracingRule::Create(config);
200 EXPECT_EQ(nullptr, rule);
201}
202
203TEST_F(BackgroundTracingRuleTest, TimerRuleFromValidProto) {
204 perfetto::protos::gen::TriggerRule config;
205 CreateRuleConfig(R"pb(
206 name: "test_rule" trigger_chance: 0.5 delay_ms: 500
207 )pb",
208 config);
209 auto rule = BackgroundTracingRule::Create(config);
210 auto result = rule->ToProtoForTesting();
211 EXPECT_EQ("test_rule", result.name());
212 EXPECT_EQ(0.5, result.trigger_chance());
213 EXPECT_EQ(500U, result.delay_ms());
214}
215
216TEST_F(BackgroundTracingRuleTest, TimerRuleTriggersAfterDelay) {
217 perfetto::protos::gen::TriggerRule config;
218 CreateRuleConfig(R"pb(
219 name: "test_rule" delay_ms: 10000
220 )pb",
221 config);
222
223 base::TimeTicks start = base::TimeTicks::Now();
224 auto rule = BackgroundTracingRule::Create(config);
225 base::RunLoop run_loop;
226 rule->Install(base::BindLambdaForTesting([&](const BackgroundTracingRule*) {
227 run_loop.Quit();
228 return true;
229 }));
230 run_loop.Run();
231 DCHECK_GE(base::TimeTicks::Now(), start + base::Milliseconds(10000));
232 rule->Uninstall();
233}
234
235TEST_F(BackgroundTracingRuleTest, RuleActivatesAfterDelay) {
236 perfetto::protos::gen::TriggerRule config;
237 CreateRuleConfig(R"pb(
238 name: "test_rule"
239 manual_trigger_name: "test_rule"
240 activation_delay_ms: 10000
241 )pb",
242 config);
243
244 auto rule = BackgroundTracingRule::Create(config);
245
246 base::RunLoop run_loop;
247 rule->Install(base::BindLambdaForTesting([&](const BackgroundTracingRule*) {
248 run_loop.Quit();
249 return true;
250 }));
251
252 // Rule is not activated yet.
253 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("test_rule"));
254 task_environment_.FastForwardBy(base::Seconds(10));
255 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("test_rule"));
256 run_loop.Run();
257 rule->Uninstall();
258}
259
260TEST_F(BackgroundTracingRuleTest, RepeatingIntervalRuleFromValidProto) {
261 perfetto::protos::gen::TriggerRule config;
262 CreateRuleConfig(
263 R"pb(
264 name: "test_rule"
265 trigger_chance: 0.5
266 delay_ms: 500
267 repeating_interval: { period_ms: 1000 randomized: true }
268 )pb",
269 config);
270 auto rule = BackgroundTracingRule::Create(config);
271 auto result = rule->ToProtoForTesting();
272 EXPECT_EQ("test_rule", result.name());
273 EXPECT_EQ(0.5, result.trigger_chance());
274 EXPECT_EQ(500U, result.delay_ms());
275 EXPECT_TRUE(result.has_repeating_interval());
276 EXPECT_EQ(1000U, result.repeating_interval().period_ms());
277 EXPECT_TRUE(result.repeating_interval().randomized());
278}
279
280TEST_F(BackgroundTracingRuleTest, RepeatingIntervalRuleTriggersAfterDelay) {
281 perfetto::protos::gen::TriggerRule config;
282 CreateRuleConfig(R"pb(
283 name: "test_rule"
284 repeating_interval: { period_ms: 2000 }
285 )pb",
286 config);
287
288 base::TimeTicks start = base::TimeTicks::Now();
289 auto rule = BackgroundTracingRule::Create(config);
290 std::vector<base::TimeTicks> trigger_times;
291 auto callback = base::BindLambdaForTesting([&](const BackgroundTracingRule*) {
292 trigger_times.push_back(base::TimeTicks::Now());
293 return true;
294 });
295 rule->Install(callback);
296 task_environment_.FastForwardBy(base::Seconds(2)); // Triggers at 2s
297 rule->Uninstall();
298 task_environment_.FastForwardBy(base::Seconds(1));
299 rule->Install(callback);
300 task_environment_.FastForwardBy(base::Seconds(2)); // Triggers at 4s
301 rule->Uninstall();
302 task_environment_.FastForwardBy(base::Seconds(2)); // Skips 6s
303 rule->Install(callback);
304 task_environment_.FastForwardBy(base::Seconds(1)); // Triggers at 8s
305
306 EXPECT_EQ(std::vector<base::TimeTicks>({
307 start + base::Seconds(2),
308 start + base::Seconds(4),
309 start + base::Seconds(8),
310 }),
311 trigger_times);
312 rule->Uninstall();
313}
314
315TEST_F(BackgroundTracingRuleTest, RepeatingIntervalRuleTriggersRandomized) {
316 perfetto::protos::gen::TriggerRule config;
317 CreateRuleConfig(
318 R"pb(
319 name: "test_rule"
320 repeating_interval: { period_ms: 2000 randomized: true }
321 )pb",
322 config);
323
324 base::TimeTicks start = base::TimeTicks::Now();
325 auto rule = BackgroundTracingRule::Create(config);
326 std::vector<base::TimeTicks> trigger_times;
327 auto callback = base::BindLambdaForTesting([&](const BackgroundTracingRule*) {
328 trigger_times.push_back(base::TimeTicks::Now());
329 return true;
330 });
331 rule->Install(callback);
332 task_environment_.FastForwardBy(base::Seconds(4)); // Triggers twice
333 ASSERT_EQ(2U, trigger_times.size());
334 EXPECT_GE(trigger_times[0], start);
335 EXPECT_LT(trigger_times[0], trigger_times[1]);
336 EXPECT_GE(trigger_times[1], start + base::Seconds(2));
337 rule->Uninstall();
338}
339
340} // namespace content