blob: 1b2425a84233e3969a76b93016cdb1886423a504 [file] [log] [blame]
Etienne Pierre-doraybb577032023-06-24 04:44:281// 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 "content/browser/tracing/tracing_scenario.h"
Etienne Pierre-doray9c0b4c62024-11-08 14:00:166
Etienne Pierre-doraybb577032023-06-24 04:44:287#include <memory>
8
9#include "base/files/file_path.h"
Daniel Cheng4f1c5332025-06-19 19:37:2110#include "base/notimplemented.h"
Etienne Pierre-doraybb577032023-06-24 04:44:2811#include "base/path_service.h"
12#include "base/task/thread_pool.h"
13#include "base/test/gmock_callback_support.h"
14#include "base/test/test_proto_loader.h"
Etienne Pierre-doray9c0b4c62024-11-08 14:00:1615#include "base/token.h"
Etienne Pierre-doray6b4f7842024-02-15 18:34:0116#include "base/trace_event/named_trigger.h"
Chinglin Yu6e022962025-01-30 10:23:2617#include "build/build_config.h"
Etienne Pierre-doraybb577032023-06-24 04:44:2818#include "content/public/browser/background_tracing_manager.h"
Etienne Pierre-doray3dc2c7dc2025-06-12 12:06:3319#include "content/public/browser/tracing_delegate.h"
Etienne Pierre-doraybb577032023-06-24 04:44:2820#include "content/public/test/browser_task_environment.h"
Etienne Pierre-doray35b4fc72024-12-16 20:05:5521#include "services/tracing/perfetto/test_utils.h"
22#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
Etienne Pierre-doraybb577032023-06-24 04:44:2823#include "testing/gmock/include/gmock/gmock.h"
24#include "testing/gtest/include/gtest/gtest.h"
25
Chinglin Yu6e022962025-01-30 10:23:2626#if BUILDFLAG(IS_POSIX)
27#include "base/files/scoped_temp_dir.h"
28#include "base/task/current_thread.h"
29#include "base/test/bind.h"
30#include "base/test/scoped_feature_list.h"
31#include "services/tracing/perfetto/system_test_utils.h"
32#include "services/tracing/public/cpp/tracing_features.h"
33#include "services/tracing/tracing_service.h"
34#endif // BUILDFLAG(IS_POSIX)
35
Etienne Pierre-doraybb577032023-06-24 04:44:2836namespace content {
37namespace {
38
Etienne Pierre-doray8a78cda2023-10-06 14:50:1739const char* kDefaultNestedConfig = R"pb(
40 scenario_name: "test_nested_scenario"
Etienne Pierre-dorayd8efb742025-02-26 15:13:3041 start_rules: { manual_trigger_name: "start_trigger" }
42 stop_rules: { manual_trigger_name: "stop_trigger" }
43 upload_rules: { manual_trigger_name: "upload_trigger" }
Etienne Pierre-doray8a78cda2023-10-06 14:50:1744)pb";
45
Etienne Pierre-doraybb577032023-06-24 04:44:2846const char* kDefaultConfig = R"pb(
47 scenario_name: "test_scenario"
Etienne Pierre-dorayd8efb742025-02-26 15:13:3048 setup_rules: { manual_trigger_name: "setup_trigger" }
49 start_rules: { manual_trigger_name: "start_trigger" }
50 stop_rules: { manual_trigger_name: "stop_trigger" }
51 upload_rules: { manual_trigger_name: "upload_trigger" }
Etienne Pierre-doraybb577032023-06-24 04:44:2852 trace_config: {
Etienne Pierre-doraya9d9c412025-06-18 15:33:4153 data_sources: { config: { name: "org.chromium.trace_metadata2" } }
Etienne Pierre-doraybb577032023-06-24 04:44:2854 }
Etienne Pierre-doray8a78cda2023-10-06 14:50:1755 nested_scenarios: {
56 scenario_name: "nested_scenario"
Etienne Pierre-dorayd8efb742025-02-26 15:13:3057 start_rules: { manual_trigger_name: "nested_start_trigger" }
58 stop_rules: { manual_trigger_name: "nested_stop_trigger" }
59 upload_rules: { manual_trigger_name: "nested_upload_trigger" }
Etienne Pierre-doray8a78cda2023-10-06 14:50:1760 }
61 nested_scenarios: {
62 scenario_name: "other_nested_scenario"
Etienne Pierre-dorayd8efb742025-02-26 15:13:3063 start_rules: { manual_trigger_name: "other_nested_start_trigger" }
64 stop_rules: { manual_trigger_name: "other_nested_stop_trigger" }
65 upload_rules: { manual_trigger_name: "other_nested_upload_trigger" }
Etienne Pierre-doray8a78cda2023-10-06 14:50:1766 }
Etienne Pierre-doraybb577032023-06-24 04:44:2867)pb";
68
69using testing::_;
70
71class TestTracingScenarioDelegate : public TracingScenario::Delegate {
72 public:
73 ~TestTracingScenarioDelegate() = default;
74
Etienne Pierre-doray98ecab42023-09-25 17:35:5875 MOCK_METHOD(bool, OnScenarioActive, (TracingScenario * scenario), (override));
76 MOCK_METHOD(bool, OnScenarioIdle, (TracingScenario * scenario), (override));
Etienne Pierre-doray9c0b4c62024-11-08 14:00:1677 MOCK_METHOD(bool, OnScenarioCloned, (TracingScenario * scenario), (override));
Etienne Pierre-doraybb577032023-06-24 04:44:2878 MOCK_METHOD(void,
Etienne Pierre-doray9653cf82025-02-07 17:08:5079 OnScenarioError,
80 (TracingScenario * scenario, perfetto::TracingError),
81 (override));
82 MOCK_METHOD(void,
Etienne Pierre-doray825d20a12023-07-10 18:24:4483 OnScenarioRecording,
84 (TracingScenario * scenario),
85 (override));
86 MOCK_METHOD(void,
Etienne Pierre-doraybb577032023-06-24 04:44:2887 SaveTrace,
Etienne Pierre-doraybd38b0752023-09-05 22:42:4688 (TracingScenario * scenario,
Etienne Pierre-doray14445052023-12-08 17:46:2289 base::Token trace_uuid,
Etienne Pierre-doraybd38b0752023-09-05 22:42:4690 const BackgroundTracingRule* triggered_rule,
91 std::string&& trace_data),
Etienne Pierre-doraybb577032023-06-24 04:44:2892 (override));
93};
94
Etienne Pierre-doray8a78cda2023-10-06 14:50:1795class TestNestedTracingScenarioDelegate
96 : public NestedTracingScenario::Delegate {
97 public:
98 ~TestNestedTracingScenarioDelegate() = default;
99
100 MOCK_METHOD(void,
101 OnNestedScenarioStart,
102 (NestedTracingScenario * scenario),
103 (override));
104 MOCK_METHOD(void,
105 OnNestedScenarioStop,
106 (NestedTracingScenario * scenario),
107 (override));
108 MOCK_METHOD(void,
109 OnNestedScenarioUpload,
110 (NestedTracingScenario * scenario,
111 const BackgroundTracingRule* triggered_rule),
112 (override));
113};
114
Etienne Pierre-doraybb577032023-06-24 04:44:28115// Fake perfetto::TracingSession.
116class TestTracingSession : public perfetto::TracingSession {
117 public:
Etienne Pierre-doray9c0b4c62024-11-08 14:00:16118 static constexpr base::Token kClonedSessionId = base::Token(0xAB, 0xCD);
119
Etienne Pierre-doraybb577032023-06-24 04:44:28120 TestTracingSession() = default;
121 ~TestTracingSession() override = default;
122
123 void Setup(const perfetto::TraceConfig& config, int fd = -1) override {
124 if (!config.data_sources().empty()) {
125 start_should_fail_ =
126 config.data_sources()[0].config().name() == "Invalid";
Etienne Pierre-doray64542e642023-07-24 17:00:52127 should_spuriously_stop =
128 config.data_sources()[0].config().name() == "Stop";
Etienne Pierre-doraybb577032023-06-24 04:44:28129 }
130 }
131
132 void Start() override {
133 if (start_should_fail_) {
134 base::ThreadPool::PostTask(
135 FROM_HERE,
136 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
137 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
138 base::BindOnce(
139 [](std::function<void(perfetto::TracingError)> // nocheck
140 on_error_callback) {
141 on_error_callback(
142 {perfetto::TracingError::kTracingFailed, "error"});
143 },
144 on_error_callback_));
145 return;
146 }
Etienne Pierre-doray64542e642023-07-24 17:00:52147 if (should_spuriously_stop) {
148 Stop();
149 return;
150 }
Etienne Pierre-doraybb577032023-06-24 04:44:28151 // perfetto::TracingSession runs callbacks from its own background thread.
152 base::ThreadPool::PostTask(
153 FROM_HERE,
154 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
155 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
156 base::BindOnce(
157 [](std::function<void()> on_start_callback) { // nocheck
158 on_start_callback();
159 },
160 on_start_callback_));
161 }
162
163 void StartBlocking() override { NOTIMPLEMENTED(); }
164
165 void SetOnStartCallback(std::function<void()> on_start) override { // nocheck
166 on_start_callback_ = on_start;
167 }
168
169 void SetOnErrorCallback(
170 std::function<void(perfetto::TracingError)> on_error) // nocheck
171 override {
172 on_error_callback_ = on_error;
173 }
174
175 void Flush(std::function<void(bool)>, uint32_t timeout_ms = 0) // nocheck
176 override {
177 NOTIMPLEMENTED();
178 }
179
180 void Stop() override {
181 // perfetto::TracingSession runs callbacks from its own background thread.
182 base::ThreadPool::PostTask(
183 FROM_HERE,
184 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
185 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
186 base::BindOnce(
187 [](std::function<void()> on_stop_callback) { // nocheck
188 on_stop_callback();
189 },
190 on_stop_callback_));
191 }
192
Etienne Pierre-doray9c0b4c62024-11-08 14:00:16193 void CloneTrace(CloneTraceArgs args,
194 CloneTraceCallback on_session_cloned) override {
195 // perfetto::TracingSession runs callbacks from its own background thread.
196 base::ThreadPool::PostTask(
197 FROM_HERE,
198 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
199 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
200 base::BindOnce(
201 [](CloneTraceCallback on_session_cloned) { // nocheck
202 on_session_cloned(
203 {true, "", kClonedSessionId.low(), kClonedSessionId.high()});
204 },
205 on_session_cloned));
206 }
207
Etienne Pierre-doraybb577032023-06-24 04:44:28208 void StopBlocking() override { NOTIMPLEMENTED(); }
209
210 void SetOnStopCallback(std::function<void()> on_stop) override { // nocheck
211 on_stop_callback_ = on_stop;
212 }
213
214 void ChangeTraceConfig(const perfetto::TraceConfig&) override {
215 NOTIMPLEMENTED();
216 }
217 void ReadTrace(ReadTraceCallback read_callback) override {
218 base::ThreadPool::PostTask(
219 FROM_HERE,
220 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
221 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
222 base::BindOnce(
223 [](ReadTraceCallback read_callback) { // nocheck
224 std::string trace_content = "this is a trace";
225 read_callback({trace_content.data(), trace_content.size(),
226 /*has_more=*/false});
227 },
228 read_callback));
229 }
230 void GetTraceStats(GetTraceStatsCallback) override { NOTIMPLEMENTED(); }
231 void QueryServiceState(QueryServiceStateCallback) override {
232 NOTIMPLEMENTED();
233 }
234
235 private:
236 std::function<void()> on_start_callback_; // nocheck
237 std::function<void()> on_stop_callback_; // nocheck
238 std::function<void(perfetto::TracingError)> on_error_callback_; // nocheck
239 bool start_should_fail_ = false;
Etienne Pierre-doray64542e642023-07-24 17:00:52240 bool should_spuriously_stop = false;
Etienne Pierre-doraybb577032023-06-24 04:44:28241};
242
243class TracingScenarioForTesting : public TracingScenario {
244 public:
245 TracingScenarioForTesting(const perfetto::protos::gen::ScenarioConfig& config,
246 TestTracingScenarioDelegate* delegate)
Etienne Pierre-doray0af80e72024-06-28 18:25:29247 : TracingScenario(config,
248 delegate,
249 /*enable_privacy_filter=*/false,
Etienne Pierre-dorayffeda342024-11-05 21:47:47250 /*is_local_scenario=*/true,
Etienne Pierre-doray86adf9d2025-01-22 18:46:25251 /*request_startup_tracing=*/false) {
Etienne Pierre-doray89055052024-04-02 19:51:39252 EXPECT_TRUE(Initialize(config, false));
Etienne Pierre-doray3e01b522023-10-10 15:38:38253 }
Etienne Pierre-doraybb577032023-06-24 04:44:28254
255 protected:
256 std::unique_ptr<perfetto::TracingSession> CreateTracingSession() override {
257 return std::make_unique<TestTracingSession>();
258 }
259};
260
Etienne Pierre-doray3e01b522023-10-10 15:38:38261class NestedTracingScenarioForTesting : public NestedTracingScenario {
262 public:
263 NestedTracingScenarioForTesting(
264 const perfetto::protos::gen::NestedScenarioConfig& config,
265 NestedTracingScenario::Delegate* delegate)
266 : NestedTracingScenario(config, delegate) {
267 EXPECT_TRUE(Initialize(config));
268 }
269};
270
Etienne Pierre-doraybb577032023-06-24 04:44:28271perfetto::protos::gen::ScenarioConfig ParseScenarioConfigFromText(
272 const std::string& proto_text) {
273 base::TestProtoLoader config_loader(
274 base::PathService::CheckedGet(base::DIR_GEN_TEST_DATA_ROOT)
275 .Append(
276 FILE_PATH_LITERAL("third_party/perfetto/protos/perfetto/"
277 "config/chrome/scenario_config.descriptor")),
278 "perfetto.protos.ScenarioConfig");
279 std::string serialized_message;
280 config_loader.ParseFromText(proto_text, serialized_message);
281 perfetto::protos::gen::ScenarioConfig destination;
282 destination.ParseFromString(serialized_message);
283 return destination;
284}
285
Etienne Pierre-doray8a78cda2023-10-06 14:50:17286perfetto::protos::gen::NestedScenarioConfig ParseNestedScenarioConfigFromText(
287 const std::string& proto_text) {
288 base::TestProtoLoader config_loader(
289 base::PathService::CheckedGet(base::DIR_GEN_TEST_DATA_ROOT)
290 .Append(
291 FILE_PATH_LITERAL("third_party/perfetto/protos/perfetto/"
292 "config/chrome/scenario_config.descriptor")),
293 "perfetto.protos.NestedScenarioConfig");
294 std::string serialized_message;
295 config_loader.ParseFromText(proto_text, serialized_message);
296 perfetto::protos::gen::NestedScenarioConfig destination;
297 destination.ParseFromString(serialized_message);
298 return destination;
299}
300
Etienne Pierre-doraybb577032023-06-24 04:44:28301class TracingScenarioTest : public testing::Test {
Etienne Pierre-doray44477e152023-07-05 14:18:27302 public:
303 TracingScenarioTest()
304 : background_tracing_manager_(
Etienne Pierre-doray3dc2c7dc2025-06-12 12:06:33305 content::BackgroundTracingManager::CreateInstance(
306 &tracing_delegate_)) {}
Etienne Pierre-doray44477e152023-07-05 14:18:27307
Etienne Pierre-doraybb577032023-06-24 04:44:28308 protected:
309 BrowserTaskEnvironment task_environment;
Etienne Pierre-doray35b4fc72024-12-16 20:05:55310 tracing::TracedProcessForTesting traced_process{
311 base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})};
Etienne Pierre-doraybb577032023-06-24 04:44:28312 TestTracingScenarioDelegate delegate;
Etienne Pierre-doray8a78cda2023-10-06 14:50:17313 TestNestedTracingScenarioDelegate nested_delegate;
Etienne Pierre-doray3dc2c7dc2025-06-12 12:06:33314 content::TracingDelegate tracing_delegate_;
Etienne Pierre-doray8a78cda2023-10-06 14:50:17315 std::unique_ptr<content::BackgroundTracingManager>
316 background_tracing_manager_;
317};
318
319class NestedTracingScenarioTest : public testing::Test {
320 public:
321 NestedTracingScenarioTest()
322 : background_tracing_manager_(
Etienne Pierre-doray3dc2c7dc2025-06-12 12:06:33323 content::BackgroundTracingManager::CreateInstance(
324 &tracing_delegate_)) {}
Etienne Pierre-doray8a78cda2023-10-06 14:50:17325
326 protected:
327 BrowserTaskEnvironment task_environment;
328 TestNestedTracingScenarioDelegate delegate;
Etienne Pierre-doray3dc2c7dc2025-06-12 12:06:33329 content::TracingDelegate tracing_delegate_;
Etienne Pierre-doray44477e152023-07-05 14:18:27330 std::unique_ptr<content::BackgroundTracingManager>
331 background_tracing_manager_;
Etienne Pierre-doraybb577032023-06-24 04:44:28332};
333
334} // namespace
335
336TEST_F(TracingScenarioTest, Init) {
337 TracingScenarioForTesting tracing_scenario(
338 ParseScenarioConfigFromText(R"pb(
339 scenario_name: "test_scenario"
340 trace_config: {
Etienne Pierre-doraya9d9c412025-06-18 15:33:41341 data_sources: { config: { name: "org.chromium.trace_metadata2" } }
Etienne Pierre-doraybb577032023-06-24 04:44:28342 }
343 )pb"),
344 &delegate);
345 EXPECT_EQ("test_scenario", tracing_scenario.scenario_name());
346 EXPECT_EQ(TracingScenario::State::kDisabled,
347 tracing_scenario.current_state());
348}
349
350TEST_F(TracingScenarioTest, Disabled) {
351 TracingScenarioForTesting tracing_scenario(
352 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
353
354 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario)).Times(0);
355
Etienne Pierre-doray6b4f7842024-02-15 18:34:01356 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("setup_trigger"));
357 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("start_trigger"));
358 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("nested_start_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28359
360 tracing_scenario.Enable();
361 EXPECT_EQ(TracingScenario::State::kEnabled, tracing_scenario.current_state());
362 tracing_scenario.Disable();
363 EXPECT_EQ(TracingScenario::State::kDisabled,
364 tracing_scenario.current_state());
365
Etienne Pierre-doray6b4f7842024-02-15 18:34:01366 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("setup_trigger"));
367 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("start_trigger"));
368 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("nested_start_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28369}
370
371TEST_F(TracingScenarioTest, StartStop) {
372 TracingScenarioForTesting tracing_scenario(
373 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
374
375 tracing_scenario.Enable();
376 EXPECT_EQ(TracingScenario::State::kEnabled, tracing_scenario.current_state());
Etienne Pierre-doray98ecab42023-09-25 17:35:58377 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
378 .WillOnce(testing::Return(true));
Etienne Pierre-doray6b4f7842024-02-15 18:34:01379 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28380
381 base::RunLoop run_loop;
382 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
Etienne Pierre-doray98ecab42023-09-25 17:35:58383 .WillOnce([&run_loop]() {
384 run_loop.Quit();
385 return true;
386 });
Etienne Pierre-doraybb577032023-06-24 04:44:28387
Etienne Pierre-doray6b4f7842024-02-15 18:34:01388 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28389 run_loop.Run();
390 EXPECT_EQ(TracingScenario::State::kDisabled,
391 tracing_scenario.current_state());
392}
393
Etienne Pierre-doray86adf9d2025-01-22 18:46:25394TEST_F(TracingScenarioTest, NestedStartStop) {
Etienne Pierre-doray8a78cda2023-10-06 14:50:17395 TracingScenarioForTesting tracing_scenario(
396 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
397
398 tracing_scenario.Enable();
399 EXPECT_EQ(TracingScenario::State::kEnabled, tracing_scenario.current_state());
400 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
401 .WillOnce(testing::Return(true));
Etienne Pierre-doray6b4f7842024-02-15 18:34:01402 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
403 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("nested_start_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17404
Etienne Pierre-doray6b4f7842024-02-15 18:34:01405 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("nested_stop_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17406
407 base::RunLoop run_loop;
408 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
409 .WillOnce([&run_loop]() {
410 run_loop.Quit();
411 return true;
412 });
413
Etienne Pierre-doray6b4f7842024-02-15 18:34:01414 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17415 run_loop.Run();
416 EXPECT_EQ(TracingScenario::State::kDisabled,
417 tracing_scenario.current_state());
418}
419
Etienne Pierre-dorayf704b172025-06-17 23:49:44420TEST_F(TracingScenarioTest, UnnestedStop) {
421 TracingScenarioForTesting tracing_scenario(
422 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
423
424 tracing_scenario.Enable();
425 EXPECT_EQ(TracingScenario::State::kEnabled, tracing_scenario.current_state());
426 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
427 .WillOnce(testing::Return(true));
428 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
429 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("nested_start_trigger"));
430
431 base::RunLoop run_loop;
432 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
433 .WillOnce([&run_loop]() {
434 run_loop.Quit();
435 return true;
436 });
437
438 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
439 run_loop.Run();
440 EXPECT_EQ(TracingScenario::State::kDisabled,
441 tracing_scenario.current_state());
442}
443
Etienne Pierre-dorayd645dd472025-07-22 14:35:04444TEST_F(TracingScenarioTest, UnnestedStopUpload) {
445 TracingScenarioForTesting tracing_scenario(
446 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
447
448 tracing_scenario.Enable();
449 EXPECT_EQ(TracingScenario::State::kEnabled, tracing_scenario.current_state());
450 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
451 .WillOnce(testing::Return(true));
452 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
453 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("nested_start_trigger"));
454
455 base::RunLoop run_loop;
456 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
457 .WillOnce([&run_loop]() {
458 run_loop.Quit();
459 return true;
460 });
461
462 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
463 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("nested_upload_trigger"));
464 run_loop.Run();
465 EXPECT_EQ(TracingScenario::State::kDisabled,
466 tracing_scenario.current_state());
467}
468
Etienne Pierre-doraybb577032023-06-24 04:44:28469TEST_F(TracingScenarioTest, StartFail) {
470 TracingScenarioForTesting tracing_scenario(
471 ParseScenarioConfigFromText(R"pb(
472 scenario_name: "test_scenario"
473 start_rules: {
474 name: "start_trigger"
475 manual_trigger_name: "start_trigger"
476 }
477 stop_rules: { name: "stop_trigger" manual_trigger_name: "stop_trigger" }
478 trace_config: { data_sources: { config: { name: "Invalid" } } }
479 )pb"),
480 &delegate);
481
482 tracing_scenario.Enable();
483 EXPECT_EQ(TracingScenario::State::kEnabled, tracing_scenario.current_state());
Etienne Pierre-doray98ecab42023-09-25 17:35:58484 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
485 .WillOnce(testing::Return(true));
Etienne Pierre-doray6b4f7842024-02-15 18:34:01486 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28487
488 base::RunLoop run_loop;
489 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
Etienne Pierre-doray98ecab42023-09-25 17:35:58490 .WillOnce([&run_loop]() {
491 run_loop.Quit();
492 return true;
493 });
Etienne Pierre-doraybb577032023-06-24 04:44:28494
495 run_loop.Run();
496 EXPECT_EQ(TracingScenario::State::kDisabled,
497 tracing_scenario.current_state());
Etienne Pierre-doray6b4f7842024-02-15 18:34:01498 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("stop_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28499}
500
Etienne Pierre-doray64542e642023-07-24 17:00:52501TEST_F(TracingScenarioTest, SpuriousStop) {
502 TracingScenarioForTesting tracing_scenario(
503 ParseScenarioConfigFromText(R"pb(
504 scenario_name: "test_scenario"
505 start_rules: {
506 name: "start_trigger"
507 manual_trigger_name: "start_trigger"
508 }
509 stop_rules: { name: "stop_trigger" manual_trigger_name: "stop_trigger" }
510 trace_config: { data_sources: { config: { name: "Stop" } } }
511 )pb"),
512 &delegate);
513
514 tracing_scenario.Enable();
515 EXPECT_EQ(TracingScenario::State::kEnabled, tracing_scenario.current_state());
Etienne Pierre-doray98ecab42023-09-25 17:35:58516 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
517 .WillOnce(testing::Return(true));
Etienne Pierre-doray6b4f7842024-02-15 18:34:01518 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
Etienne Pierre-doray64542e642023-07-24 17:00:52519
520 base::RunLoop run_loop;
521 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
Etienne Pierre-doray98ecab42023-09-25 17:35:58522 .WillOnce([&run_loop]() {
523 run_loop.Quit();
524 return true;
525 });
Etienne Pierre-doray64542e642023-07-24 17:00:52526
527 run_loop.Run();
528 EXPECT_EQ(TracingScenario::State::kDisabled,
529 tracing_scenario.current_state());
Etienne Pierre-doray6b4f7842024-02-15 18:34:01530 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("stop_trigger"));
Etienne Pierre-doray64542e642023-07-24 17:00:52531}
532
Etienne Pierre-doraybb577032023-06-24 04:44:28533TEST_F(TracingScenarioTest, SetupStop) {
534 TracingScenarioForTesting tracing_scenario(
535 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
536
537 tracing_scenario.Enable();
Etienne Pierre-doray98ecab42023-09-25 17:35:58538 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
539 .WillOnce(testing::Return(true));
Etienne Pierre-doray6b4f7842024-02-15 18:34:01540 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("setup_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28541 EXPECT_EQ(TracingScenario::State::kSetup, tracing_scenario.current_state());
542
543 base::RunLoop run_loop;
544 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
Etienne Pierre-doray98ecab42023-09-25 17:35:58545 .WillOnce([&run_loop]() {
546 run_loop.Quit();
547 return true;
548 });
Etienne Pierre-doraybb577032023-06-24 04:44:28549
Etienne Pierre-doray6b4f7842024-02-15 18:34:01550 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28551 run_loop.Run();
552 EXPECT_EQ(TracingScenario::State::kDisabled,
553 tracing_scenario.current_state());
554}
555
556TEST_F(TracingScenarioTest, SetupUpload) {
557 TracingScenarioForTesting tracing_scenario(
558 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
559
560 tracing_scenario.Enable();
Etienne Pierre-doray98ecab42023-09-25 17:35:58561 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
562 .WillOnce(testing::Return(true));
Etienne Pierre-doray6b4f7842024-02-15 18:34:01563 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("setup_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28564 EXPECT_EQ(TracingScenario::State::kSetup, tracing_scenario.current_state());
565
Etienne Pierre-doray14445052023-12-08 17:46:22566 base::Token trace_uuid = tracing_scenario.GetSessionID();
Etienne Pierre-doraybb577032023-06-24 04:44:28567 base::RunLoop run_loop;
Etienne Pierre-doray14445052023-12-08 17:46:22568 EXPECT_CALL(delegate, SaveTrace(_, trace_uuid, _, _)).Times(0);
Etienne Pierre-doraybb577032023-06-24 04:44:28569 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
Etienne Pierre-doray98ecab42023-09-25 17:35:58570 .WillOnce([&run_loop]() {
571 run_loop.Quit();
572 return true;
573 });
Etienne Pierre-doraybb577032023-06-24 04:44:28574
Etienne Pierre-doray6b4f7842024-02-15 18:34:01575 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("upload_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28576 run_loop.Run();
577 EXPECT_EQ(TracingScenario::State::kDisabled,
578 tracing_scenario.current_state());
579}
580
581TEST_F(TracingScenarioTest, SetupStartStop) {
582 TracingScenarioForTesting tracing_scenario(
583 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
584
585 tracing_scenario.Enable();
Etienne Pierre-doray98ecab42023-09-25 17:35:58586 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
587 .WillOnce(testing::Return(true));
Etienne Pierre-doray6b4f7842024-02-15 18:34:01588 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("setup_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28589 EXPECT_EQ(TracingScenario::State::kSetup, tracing_scenario.current_state());
590
591 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario)).Times(0);
Etienne Pierre-doray6b4f7842024-02-15 18:34:01592 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
Etienne Pierre-dorayd8efb742025-02-26 15:13:30593 EXPECT_EQ(TracingScenario::State::kStarting,
Etienne Pierre-doraybb577032023-06-24 04:44:28594 tracing_scenario.current_state());
595
596 base::RunLoop run_loop;
597 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
Etienne Pierre-doray98ecab42023-09-25 17:35:58598 .WillOnce([&run_loop]() {
599 run_loop.Quit();
600 return true;
601 });
Etienne Pierre-doraybb577032023-06-24 04:44:28602
Etienne Pierre-doray6b4f7842024-02-15 18:34:01603 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28604 run_loop.Run();
605 EXPECT_EQ(TracingScenario::State::kDisabled,
606 tracing_scenario.current_state());
607}
608
Etienne Pierre-doray8a78cda2023-10-06 14:50:17609TEST_F(TracingScenarioTest, SetupNestedStartStop) {
610 TracingScenarioForTesting tracing_scenario(
611 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
612
613 tracing_scenario.Enable();
614 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
615 .WillOnce(testing::Return(true));
Etienne Pierre-doray6b4f7842024-02-15 18:34:01616 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("setup_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17617 EXPECT_EQ(TracingScenario::State::kSetup, tracing_scenario.current_state());
618
619 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario)).Times(0);
Etienne Pierre-doray6b4f7842024-02-15 18:34:01620 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("nested_start_trigger"));
Etienne Pierre-dorayd8efb742025-02-26 15:13:30621 EXPECT_EQ(TracingScenario::State::kStarting,
Etienne Pierre-doray8a78cda2023-10-06 14:50:17622 tracing_scenario.current_state());
623 EXPECT_FALSE(
Etienne Pierre-doray6b4f7842024-02-15 18:34:01624 base::trace_event::EmitNamedTrigger("other_nested_start_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17625
Etienne Pierre-doray6b4f7842024-02-15 18:34:01626 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("nested_stop_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17627
628 base::RunLoop run_loop;
629 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
630 .WillOnce([&run_loop]() {
631 run_loop.Quit();
632 return true;
633 });
Etienne Pierre-doray6b4f7842024-02-15 18:34:01634 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17635 run_loop.Run();
636 EXPECT_EQ(TracingScenario::State::kDisabled,
637 tracing_scenario.current_state());
638}
639
Etienne Pierre-doraybb577032023-06-24 04:44:28640TEST_F(TracingScenarioTest, Abort) {
641 TracingScenarioForTesting tracing_scenario(
642 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
643
644 tracing_scenario.Enable();
Etienne Pierre-doray98ecab42023-09-25 17:35:58645 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
646 .WillOnce(testing::Return(true));
Etienne Pierre-doray6b4f7842024-02-15 18:34:01647 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
Etienne Pierre-dorayd8efb742025-02-26 15:13:30648 EXPECT_EQ(TracingScenario::State::kStarting,
Etienne Pierre-doraybb577032023-06-24 04:44:28649 tracing_scenario.current_state());
650
651 base::RunLoop run_loop;
652 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
Etienne Pierre-doray98ecab42023-09-25 17:35:58653 .WillOnce([&run_loop]() {
654 run_loop.Quit();
655 return true;
656 });
Etienne Pierre-doraybb577032023-06-24 04:44:28657
658 tracing_scenario.Abort();
659 run_loop.Run();
660 EXPECT_EQ(TracingScenario::State::kDisabled,
661 tracing_scenario.current_state());
Etienne Pierre-doray6b4f7842024-02-15 18:34:01662 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("stop_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28663}
664
665TEST_F(TracingScenarioTest, Upload) {
666 TracingScenarioForTesting tracing_scenario(
667 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
668
669 tracing_scenario.Enable();
Etienne Pierre-doray98ecab42023-09-25 17:35:58670 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
671 .WillOnce(testing::Return(true));
Etienne Pierre-dorayd8efb742025-02-26 15:13:30672 {
673 base::RunLoop run_loop;
674 EXPECT_CALL(delegate, OnScenarioRecording(&tracing_scenario))
675 .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
676 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
677 EXPECT_EQ(TracingScenario::State::kStarting,
678 tracing_scenario.current_state());
679 run_loop.Run();
680 EXPECT_EQ(TracingScenario::State::kRecording,
681 tracing_scenario.current_state());
682 }
Etienne Pierre-doraybb577032023-06-24 04:44:28683
Etienne Pierre-doray14445052023-12-08 17:46:22684 base::Token trace_uuid = tracing_scenario.GetSessionID();
Etienne Pierre-doraybb577032023-06-24 04:44:28685 base::RunLoop run_loop;
Etienne Pierre-doray14445052023-12-08 17:46:22686 EXPECT_CALL(delegate, SaveTrace(&tracing_scenario, trace_uuid, _,
687 std::string("this is a trace")))
Etienne Pierre-doraybb577032023-06-24 04:44:28688 .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
Etienne Pierre-doray98ecab42023-09-25 17:35:58689 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
690 .WillOnce(testing::Return(true));
Etienne Pierre-doraybb577032023-06-24 04:44:28691
Etienne Pierre-doray6b4f7842024-02-15 18:34:01692 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("upload_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28693
694 run_loop.Run();
695 EXPECT_EQ(TracingScenario::State::kDisabled,
696 tracing_scenario.current_state());
697}
698
699TEST_F(TracingScenarioTest, StopUpload) {
700 TracingScenarioForTesting tracing_scenario(
701 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
702
703 tracing_scenario.Enable();
Etienne Pierre-doray98ecab42023-09-25 17:35:58704 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
705 .WillOnce(testing::Return(true));
Etienne Pierre-dorayd8efb742025-02-26 15:13:30706 {
707 base::RunLoop run_loop;
708 EXPECT_CALL(delegate, OnScenarioRecording(&tracing_scenario))
709 .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
710 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
711 run_loop.Run();
712 }
Etienne Pierre-doraybb577032023-06-24 04:44:28713
Etienne Pierre-doray14445052023-12-08 17:46:22714 base::Token trace_uuid = tracing_scenario.GetSessionID();
Etienne Pierre-doraybb577032023-06-24 04:44:28715 base::RunLoop run_loop;
Etienne Pierre-doray14445052023-12-08 17:46:22716 EXPECT_CALL(delegate, SaveTrace(&tracing_scenario, trace_uuid, _,
717 std::string("this is a trace")))
Etienne Pierre-doraybb577032023-06-24 04:44:28718 .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
Etienne Pierre-doray98ecab42023-09-25 17:35:58719 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
720 .WillOnce(testing::Return(true));
Etienne Pierre-doraybb577032023-06-24 04:44:28721
Etienne Pierre-doray6b4f7842024-02-15 18:34:01722 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
723 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("upload_trigger"));
Etienne Pierre-doraybb577032023-06-24 04:44:28724
725 run_loop.Run();
726 EXPECT_EQ(TracingScenario::State::kDisabled,
727 tracing_scenario.current_state());
728}
729
Etienne Pierre-doray86adf9d2025-01-22 18:46:25730TEST_F(TracingScenarioTest, NestedUpload) {
Etienne Pierre-doray8a78cda2023-10-06 14:50:17731 TracingScenarioForTesting tracing_scenario(
732 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
733
734 tracing_scenario.Enable();
735 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
736 .WillOnce(testing::Return(true));
Etienne Pierre-dorayd8efb742025-02-26 15:13:30737 {
738 base::RunLoop run_loop;
739 EXPECT_CALL(delegate, OnScenarioRecording(&tracing_scenario))
740 .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
741 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
742 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("nested_start_trigger"));
743 run_loop.Run();
744 }
745 EXPECT_EQ(TracingScenario::State::kRecording,
746 tracing_scenario.current_state());
Etienne Pierre-doray8a78cda2023-10-06 14:50:17747
Etienne Pierre-doray9c0b4c62024-11-08 14:00:16748 {
749 base::RunLoop run_loop;
750 EXPECT_CALL(delegate, OnScenarioCloned(&tracing_scenario))
751 .WillOnce(testing::Return(true));
752 EXPECT_CALL(delegate, SaveTrace(&tracing_scenario,
753 TestTracingSession::kClonedSessionId, _,
754 std::string("this is a trace")))
755 .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
756 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("nested_upload_trigger"));
757 run_loop.Run();
758 }
Etienne Pierre-doray8a78cda2023-10-06 14:50:17759
Etienne Pierre-doray9c0b4c62024-11-08 14:00:16760 {
761 base::RunLoop run_loop;
762 EXPECT_EQ(TracingScenario::State::kRecording,
763 tracing_scenario.current_state());
Etienne Pierre-doray8a78cda2023-10-06 14:50:17764
Etienne Pierre-doray9c0b4c62024-11-08 14:00:16765 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
766 .WillOnce([&run_loop]() {
767 run_loop.Quit();
768 return true;
769 });
770 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
771 run_loop.Run();
772 }
Etienne Pierre-doray8a78cda2023-10-06 14:50:17773}
774
Etienne Pierre-dorayf6576d942025-04-22 17:42:13775TEST_F(TracingScenarioTest, NestedStopUpload) {
776 TracingScenarioForTesting tracing_scenario(
777 ParseScenarioConfigFromText(kDefaultConfig), &delegate);
778
779 tracing_scenario.Enable();
780 EXPECT_CALL(delegate, OnScenarioActive(&tracing_scenario))
781 .WillOnce(testing::Return(true));
782 {
783 base::RunLoop run_loop;
784 EXPECT_CALL(delegate, OnScenarioRecording(&tracing_scenario))
785 .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
786 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
787 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("nested_start_trigger"));
788 run_loop.Run();
789 }
790 EXPECT_EQ(TracingScenario::State::kRecording,
791 tracing_scenario.current_state());
792
793 {
794 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("nested_stop_trigger"));
795 base::RunLoop run_loop;
796 EXPECT_CALL(delegate, OnScenarioCloned(&tracing_scenario))
797 .WillOnce(testing::Return(true));
798 EXPECT_CALL(delegate, SaveTrace(&tracing_scenario,
799 TestTracingSession::kClonedSessionId, _,
800 std::string("this is a trace")))
801 .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
802 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("nested_upload_trigger"));
803 run_loop.Run();
804 }
805
806 {
807 base::RunLoop run_loop;
808 EXPECT_EQ(TracingScenario::State::kRecording,
809 tracing_scenario.current_state());
810
811 EXPECT_CALL(delegate, OnScenarioIdle(&tracing_scenario))
812 .WillOnce([&run_loop]() {
813 run_loop.Quit();
814 return true;
815 });
816 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
817 run_loop.Run();
818 }
819}
820
Etienne Pierre-doray8a78cda2023-10-06 14:50:17821TEST_F(NestedTracingScenarioTest, Disabled) {
Etienne Pierre-doray3e01b522023-10-10 15:38:38822 NestedTracingScenarioForTesting tracing_scenario(
Etienne Pierre-doray8a78cda2023-10-06 14:50:17823 ParseNestedScenarioConfigFromText(kDefaultNestedConfig), &delegate);
824
825 EXPECT_CALL(delegate, OnNestedScenarioStart(&tracing_scenario)).Times(0);
826
Etienne Pierre-doray6b4f7842024-02-15 18:34:01827 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("start_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17828
829 tracing_scenario.Enable();
830 EXPECT_EQ(NestedTracingScenario::State::kEnabled,
831 tracing_scenario.current_state());
832 tracing_scenario.Disable();
833 EXPECT_EQ(NestedTracingScenario::State::kDisabled,
834 tracing_scenario.current_state());
835
Etienne Pierre-doray6b4f7842024-02-15 18:34:01836 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("start_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17837}
838
839TEST_F(NestedTracingScenarioTest, StartStop) {
Etienne Pierre-doray3e01b522023-10-10 15:38:38840 NestedTracingScenarioForTesting tracing_scenario(
Etienne Pierre-doray8a78cda2023-10-06 14:50:17841 ParseNestedScenarioConfigFromText(kDefaultNestedConfig), &delegate);
842
843 tracing_scenario.Enable();
844 EXPECT_EQ(NestedTracingScenario::State::kEnabled,
845 tracing_scenario.current_state());
846 EXPECT_CALL(delegate, OnNestedScenarioStart(&tracing_scenario)).Times(1);
Etienne Pierre-doray6b4f7842024-02-15 18:34:01847 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17848
849 EXPECT_CALL(delegate, OnNestedScenarioStop(&tracing_scenario)).Times(1);
Etienne Pierre-doray6b4f7842024-02-15 18:34:01850 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17851 EXPECT_EQ(NestedTracingScenario::State::kStopping,
852 tracing_scenario.current_state());
853 tracing_scenario.Disable();
854 EXPECT_EQ(NestedTracingScenario::State::kDisabled,
855 tracing_scenario.current_state());
856}
857
858TEST_F(NestedTracingScenarioTest, Upload) {
Etienne Pierre-doray3e01b522023-10-10 15:38:38859 NestedTracingScenarioForTesting tracing_scenario(
Etienne Pierre-doray8a78cda2023-10-06 14:50:17860 ParseNestedScenarioConfigFromText(kDefaultNestedConfig), &delegate);
861
862 tracing_scenario.Enable();
863 EXPECT_CALL(delegate, OnNestedScenarioStart(&tracing_scenario)).Times(1);
Etienne Pierre-doray6b4f7842024-02-15 18:34:01864 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17865
866 EXPECT_CALL(delegate, OnNestedScenarioUpload(&tracing_scenario, _)).Times(1);
Etienne Pierre-doray6b4f7842024-02-15 18:34:01867 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("upload_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17868
869 EXPECT_EQ(NestedTracingScenario::State::kDisabled,
870 tracing_scenario.current_state());
871}
872
Etienne Pierre-doray86adf9d2025-01-22 18:46:25873TEST_F(NestedTracingScenarioTest, StopUpload) {
Etienne Pierre-doray3e01b522023-10-10 15:38:38874 NestedTracingScenarioForTesting tracing_scenario(
Etienne Pierre-doray8a78cda2023-10-06 14:50:17875 ParseNestedScenarioConfigFromText(kDefaultNestedConfig), &delegate);
876
877 tracing_scenario.Enable();
878 EXPECT_CALL(delegate, OnNestedScenarioStart(&tracing_scenario)).Times(1);
Etienne Pierre-doray6b4f7842024-02-15 18:34:01879 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17880
881 base::RunLoop run_loop;
882 EXPECT_CALL(delegate, OnNestedScenarioUpload(&tracing_scenario, _))
883 .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
884 EXPECT_CALL(delegate, OnNestedScenarioStop(&tracing_scenario)).Times(1);
885
Etienne Pierre-doray6b4f7842024-02-15 18:34:01886 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
887 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("upload_trigger"));
Etienne Pierre-doray8a78cda2023-10-06 14:50:17888
889 run_loop.Run();
890 EXPECT_EQ(NestedTracingScenario::State::kDisabled,
891 tracing_scenario.current_state());
892}
893
Chinglin Yu6e022962025-01-30 10:23:26894#if BUILDFLAG(IS_POSIX)
895
896const char* kSystemProbeScenarioConfig = R"pb(
897 scenario_name: "test_scenario"
898 setup_rules: { manual_trigger_name: "setup_trigger" }
899 start_rules: { manual_trigger_name: "start_trigger" }
900 stop_rules: { manual_trigger_name: "stop_trigger" }
901 trace_config: { data_sources: { config: { name: "mock_data_source" } } }
902 use_system_backend: true
903)pb";
904
905class TracingScenarioSystemBackendTest : public testing::Test {
906 public:
907 static constexpr char kPerfettoConsumerSockName[] =
908 "PERFETTO_CONSUMER_SOCK_NAME";
909 static constexpr char kPerfettoProducerSockName[] =
910 "PERFETTO_PRODUCER_SOCK_NAME";
911 TracingScenarioSystemBackendTest()
912 : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {}
913
914 void TearDown() override {
915 system_producer_ = nullptr;
916 system_service_ = nullptr;
917 traced_process_ = nullptr;
918
919 // Restore env variables after shutdown of the above to data races with the
920 // muxer thread.
921 if (saved_consumer_sock_name_) {
922 ASSERT_EQ(0, setenv(kPerfettoConsumerSockName,
923 saved_consumer_sock_name_->c_str(), 1));
924 } else {
925 ASSERT_EQ(0, unsetenv(kPerfettoConsumerSockName));
926 }
927 if (saved_producer_sock_name_) {
928 ASSERT_EQ(0, setenv(kPerfettoProducerSockName,
929 saved_producer_sock_name_->c_str(), 1));
930 } else {
931 ASSERT_EQ(0, unsetenv(kPerfettoConsumerSockName));
932 }
933 }
934
935 // This is not implemented as Setup() because system tracing feature flags
936 // affect the behavior of PerfettoTracedProcess::SetupClientLibrary(). The
937 // tests will need to enable/disable features before |traced_process| is
938 // created.
939 void InitTracing() {
940 // The test connects to the mock system service.
941 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
942 system_service_ = std::make_unique<tracing::MockSystemService>(temp_dir_);
943
944 const auto* env_val = getenv(kPerfettoConsumerSockName);
945 if (env_val) {
946 saved_consumer_sock_name_ = env_val;
947 }
948 ASSERT_EQ(0, setenv(kPerfettoConsumerSockName,
949 system_service_->consumer().c_str(), 1));
950
951 env_val = getenv(kPerfettoProducerSockName);
952 if (env_val) {
953 saved_producer_sock_name_ = env_val;
954 }
955 ASSERT_EQ(0, setenv(kPerfettoProducerSockName,
956 system_service_->producer().c_str(), 1));
957
958 traced_process_ = std::make_unique<tracing::TracedProcessForTesting>(
959 base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}));
960 background_tracing_manager_ =
Etienne Pierre-doray3dc2c7dc2025-06-12 12:06:33961 content::BackgroundTracingManager::CreateInstance(&tracing_delegate_);
Chinglin Yu6e022962025-01-30 10:23:26962
963 // Connect the producer to the tracing service.
964 system_producer_ = std::make_unique<tracing::MockProducer>();
965 system_producer_->Connect(system_service_->GetService(), "mock_producer");
966 system_producer_->RegisterDataSource("mock_data_source");
967
968 // Also enable the custom backend.
969 static tracing::mojom::TracingService* s_service;
970 s_service = &tracing_service_;
971 // Check if the consumer backend is used.
972 static bool* consumer_conn_created;
973 consumer_conn_created = &custom_backend_consumer_conn_created_;
974 auto factory = []() -> tracing::mojom::TracingService& {
975 *consumer_conn_created = true;
976 return *s_service;
977 };
978 tracing::PerfettoTracedProcess::Get().SetConsumerConnectionFactory(
979 factory, base::SequencedTaskRunner::GetCurrentDefault());
980
981 // Reset the callback that controls whether system consumer is allowed.
982 tracing::PerfettoTracedProcess::Get().SetAllowSystemTracingConsumerCallback(
983 base::RepeatingCallback<bool()>());
984 }
985
986 protected:
987 // Not inheriting from TracingScenarioTest because initialization of
988 // |traced_process_| depends on feature flags and environment variables.
989 BrowserTaskEnvironment task_environment_;
990 std::unique_ptr<tracing::TracedProcessForTesting> traced_process_;
991 TestTracingScenarioDelegate delegate;
Etienne Pierre-doray3dc2c7dc2025-06-12 12:06:33992 content::TracingDelegate tracing_delegate_;
Chinglin Yu6e022962025-01-30 10:23:26993 std::unique_ptr<content::BackgroundTracingManager>
994 background_tracing_manager_;
995
996 base::ScopedTempDir temp_dir_;
997 std::unique_ptr<tracing::MockSystemService> system_service_;
998 std::optional<std::string> saved_consumer_sock_name_;
999 std::optional<std::string> saved_producer_sock_name_;
1000 std::unique_ptr<tracing::MockProducer> system_producer_;
1001
1002 tracing::PerfettoService perfetto_service_;
1003 tracing::TracingService tracing_service_;
1004
1005 // Set to true when a consumer connection of the custom backend is created.
1006 bool custom_backend_consumer_conn_created_ = false;
1007};
1008
1009// Test the system backend by creating a real Perfetto tracing service thread
1010// that listens to producer and consumer sockets. Config the tracing scenario to
1011// use the system backend and check from the producer that a trace session is
1012// started and stopped through the system backend.
1013TEST_F(TracingScenarioSystemBackendTest, StartStop) {
1014 base::test::ScopedFeatureList scoped_feature_list;
1015 scoped_feature_list.InitWithFeatures(
1016 /*enabled_features=*/{features::kEnablePerfettoSystemTracing,
1017 features::kEnablePerfettoSystemBackgroundTracing},
1018 /*disabled_features=*/{});
1019 InitTracing();
1020
1021 bool allow_system_consumer_checked = false;
1022 auto callback =
1023 base::BindLambdaForTesting([&allow_system_consumer_checked]() {
1024 allow_system_consumer_checked = true;
1025 // Allow system consumer connections. This is typically checked in
1026 // ChromeTracingDelegate::IsSystemWideTracingEnabled().
1027 return true;
1028 });
1029 tracing::PerfettoTracedProcess::Get().SetAllowSystemTracingConsumerCallback(
1030 std::move(callback));
1031
1032 // Create a real tracing scenario. Under the hood the system backend is used.
1033 auto tracing_scenario = TracingScenario::Create(
1034 ParseScenarioConfigFromText(kSystemProbeScenarioConfig), false, false,
1035 false, false, &delegate);
1036
1037 tracing_scenario->Enable();
1038 EXPECT_EQ(TracingScenario::State::kEnabled,
1039 tracing_scenario->current_state());
1040 EXPECT_CALL(delegate, OnScenarioActive(tracing_scenario.get()))
1041 .WillOnce(testing::Return(true));
1042 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("setup_trigger"));
1043 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
1044
1045 // Wait until the data source is started.
1046 base::RunLoop run_loop_start;
1047 EXPECT_CALL(*system_producer_.get(), OnStartDataSource(_, _))
1048 .WillOnce([&run_loop_start]() {
1049 run_loop_start.Quit();
1050 return true;
1051 });
1052 run_loop_start.Run();
1053
1054 // Stop tracing. Wait until the data source is stopped.
1055 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
1056 base::RunLoop run_loop_stop;
1057 EXPECT_CALL(*system_producer_.get(), OnStopDataSource(_, _))
1058 .WillOnce([&run_loop_stop]() {
1059 run_loop_stop.Quit();
1060 return true;
1061 });
1062 run_loop_stop.Run();
1063
1064 // Run until the scenario is idle.
1065 base::RunLoop run_loop_idle;
1066 EXPECT_CALL(delegate, OnScenarioIdle(tracing_scenario.get()))
1067 .WillOnce([&run_loop_idle]() {
1068 run_loop_idle.Quit();
1069 return true;
1070 });
1071 run_loop_idle.Run();
1072
1073 EXPECT_EQ(TracingScenario::State::kDisabled,
1074 tracing_scenario->current_state());
1075 EXPECT_TRUE(allow_system_consumer_checked);
1076}
1077
1078// Test that system consumer connections are denied.
1079TEST_F(TracingScenarioSystemBackendTest, SystemConsumerNotAllowedByCallback) {
1080 base::test::ScopedFeatureList scoped_feature_list;
1081 scoped_feature_list.InitWithFeatures(
1082 /*enabled_features=*/{features::kEnablePerfettoSystemTracing,
1083 features::kEnablePerfettoSystemBackgroundTracing},
1084 /*disabled_features=*/{});
1085 InitTracing();
1086
1087 bool allow_system_consumer_checked = false;
1088 auto callback =
1089 base::BindLambdaForTesting([&allow_system_consumer_checked]() {
1090 allow_system_consumer_checked = true;
1091 return false; // Deny system consumer connection.
1092 });
1093
1094 tracing::PerfettoTracedProcess::Get().SetAllowSystemTracingConsumerCallback(
1095 std::move(callback));
1096
1097 // Create a real tracing scenario.
1098 auto tracing_scenario = TracingScenario::Create(
1099 ParseScenarioConfigFromText(kSystemProbeScenarioConfig), false, false,
1100 false, false, &delegate);
1101
1102 tracing_scenario->Enable();
1103 EXPECT_EQ(TracingScenario::State::kEnabled,
1104 tracing_scenario->current_state());
1105 EXPECT_CALL(delegate, OnScenarioActive(tracing_scenario.get()))
1106 .WillOnce(testing::Return(true));
1107 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("setup_trigger"));
1108 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
1109
1110 // The system data producer isn't used.
1111 EXPECT_CALL(*system_producer_.get(), OnStartDataSource(_, _)).Times(0);
1112 // The callback doesn't allow system consumer. The scenario won't be started.
1113
1114 tracing_scenario->Abort();
1115 base::RunLoop run_loop_idle;
1116 EXPECT_CALL(delegate, OnScenarioIdle(tracing_scenario.get()))
1117 .WillOnce([&run_loop_idle]() {
1118 run_loop_idle.Quit();
1119 return true;
1120 });
1121 run_loop_idle.Run();
1122 EXPECT_TRUE(allow_system_consumer_checked);
1123 // Not using the custom backend.
1124 EXPECT_FALSE(custom_backend_consumer_conn_created_);
1125}
1126
1127// The scenario is ignored if it requests to use the system backend, but the
1128// system backend is unavailable (feature
1129// "EnablePerfettoSystemBackgroundTracing" isn't enabled).
1130TEST_F(TracingScenarioSystemBackendTest, FeatureNotEnabled_1) {
1131 base::test::ScopedFeatureList scoped_feature_list;
1132 scoped_feature_list.InitWithFeatures(
1133 /*enabled_features=*/{features::kEnablePerfettoSystemTracing},
1134 /*disabled_features=*/{features::kEnablePerfettoSystemBackgroundTracing});
1135 InitTracing();
1136
1137 // Create a real tracing scenario. The system backend isn't used.
1138 auto tracing_scenario = TracingScenario::Create(
1139 ParseScenarioConfigFromText(kSystemProbeScenarioConfig), false, false,
1140 false, false, &delegate);
1141
1142 tracing_scenario->Enable();
1143 EXPECT_EQ(TracingScenario::State::kEnabled,
1144 tracing_scenario->current_state());
1145 EXPECT_CALL(delegate, OnScenarioActive(tracing_scenario.get())).Times(0);
1146 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("setup_trigger"));
1147 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("start_trigger"));
1148
1149 tracing_scenario->Disable();
1150 EXPECT_EQ(TracingScenario::State::kDisabled,
1151 tracing_scenario->current_state());
1152 // Not using the custom backend.
1153 EXPECT_FALSE(custom_backend_consumer_conn_created_);
1154}
1155
1156// EnablePerfettoSystemTracing doesn't have an effect on Android. In debugging
1157// (which is always true in content_unittests) system tracing is always enabled.
1158// Disable this test on Android.
1159#if !BUILDFLAG(IS_ANDROID)
1160// The scenario is ignored if it requests to use the system backend, but the
1161// system backend is unavailable (feature "EnablePerfettoSystemTracing" isn't
1162// enabled).
1163TEST_F(TracingScenarioSystemBackendTest, FeatureNotEnabled_2) {
1164 base::test::ScopedFeatureList scoped_feature_list;
1165 scoped_feature_list.InitWithFeatures(
1166 /*enabled_features=*/{features::kEnablePerfettoSystemBackgroundTracing},
1167 /*disabled_features=*/{features::kEnablePerfettoSystemTracing});
1168
1169 InitTracing();
1170 // Create a real tracing scenario. The system backend isn't used.
1171 auto tracing_scenario = TracingScenario::Create(
1172 ParseScenarioConfigFromText(kSystemProbeScenarioConfig), false, false,
1173 false, false, &delegate);
1174
1175 tracing_scenario->Enable();
1176 EXPECT_EQ(TracingScenario::State::kEnabled,
1177 tracing_scenario->current_state());
1178 EXPECT_CALL(delegate, OnScenarioActive(tracing_scenario.get())).Times(0);
1179 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("setup_trigger"));
1180 EXPECT_FALSE(base::trace_event::EmitNamedTrigger("start_trigger"));
1181
1182 tracing_scenario->Disable();
1183 EXPECT_EQ(TracingScenario::State::kDisabled,
1184 tracing_scenario->current_state());
1185 // Not using the custom backend.
1186 EXPECT_FALSE(custom_backend_consumer_conn_created_);
1187}
1188#endif
1189
1190const char* kScenarioConfigWithoutSystemBackend = R"pb(
1191 scenario_name: "test_scenario"
1192 setup_rules: { manual_trigger_name: "setup_trigger" }
1193 start_rules: { manual_trigger_name: "start_trigger" }
1194 stop_rules: { manual_trigger_name: "stop_trigger" }
1195 trace_config: { data_sources: { config: { name: "mock_data_source" } } }
1196)pb";
1197
1198// The custom backend is used on a platform that has system background tracing
1199// enabled if the scenario doesn't specify the system backend
1200TEST_F(TracingScenarioSystemBackendTest, ScenarioConfigWithoutSystemBackend) {
1201 base::test::ScopedFeatureList scoped_feature_list;
1202 scoped_feature_list.InitWithFeatures(
1203 /*enabled_features=*/{features::kEnablePerfettoSystemTracing,
1204 features::kEnablePerfettoSystemBackgroundTracing},
1205 /*disabled_features=*/{});
1206
1207 InitTracing();
1208
1209 // Create a real tracing scenario. The system backend isn't used.
1210 auto tracing_scenario = TracingScenario::Create(
1211 ParseScenarioConfigFromText(kScenarioConfigWithoutSystemBackend), false,
1212 false, false, false, &delegate);
1213
1214 tracing_scenario->Enable();
1215 EXPECT_EQ(TracingScenario::State::kEnabled,
1216 tracing_scenario->current_state());
1217 EXPECT_CALL(delegate, OnScenarioActive(tracing_scenario.get()))
1218 .WillOnce(testing::Return(true));
1219 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("setup_trigger"));
1220 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("start_trigger"));
1221
1222 // The system data producer isn't used.
1223 EXPECT_CALL(*system_producer_.get(), OnStartDataSource(_, _)).Times(0);
1224 // Instead, the custom backend connection factory is called.
1225 base::test::RunUntil([&]() { return custom_backend_consumer_conn_created_; });
1226
1227 EXPECT_TRUE(base::trace_event::EmitNamedTrigger("stop_trigger"));
1228 // Not waiting until OnScenarioIdle because mojo of |tracing_service_| isn't
1229 // fully set up.
1230}
1231
1232#endif // BUILDFLAG(IS_POSIX)
1233
Etienne Pierre-doraybb577032023-06-24 04:44:281234} // namespace content