blob: 9749aac36b9fe68ae52d9160c88cd7407ee532f5 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/tracing/public/cpp/trace_event_agent.h"
#include <utility>
#include "base/bind.h"
#include "base/callback_forward.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "base/test/trace_event_analyzer.h"
#include "base/time/time.h"
#include "base/trace_event/trace_config.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_log.h"
#include "base/values.h"
#include "services/tracing/public/mojom/tracing.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace tracing {
namespace {
constexpr const char kTestCategory[] = "TraceEventAgentTestCategory";
const char kTestMetadataKey[] = "TraceEventAgentTestMetadata";
} // namespace
class MockRecorder : public mojom::Recorder {
public:
explicit MockRecorder(mojom::RecorderRequest request)
: binding_(this, std::move(request)) {
binding_.set_connection_error_handler(base::BindRepeating(
&MockRecorder::OnConnectionError, base::Unretained(this)));
}
std::string events() const { return events_; }
std::string metadata() const { return metadata_; }
void set_quit_closure(base::Closure quit_closure) {
quit_closure_ = quit_closure;
}
private:
void Append(std::string* dest, const std::string& chunk) {
if (chunk.empty())
return;
if (!dest->empty())
dest->push_back(',');
dest->append(chunk);
}
void AddChunk(const std::string& chunk) override {
std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer(
trace_analyzer::TraceAnalyzer::Create("[" + chunk + "]"));
trace_analyzer::TraceEventVector events;
analyzer->FindEvents(trace_analyzer::Query::EventCategoryIs(kTestCategory),
&events);
for (const auto* event : events) {
Append(&events_, event->name);
}
}
void AddMetadata(base::Value metadata) override {
base::DictionaryValue* dict = nullptr;
EXPECT_TRUE(metadata.GetAsDictionary(&dict));
std::string value;
if (dict->GetString(kTestMetadataKey, &value))
Append(&metadata_, value);
}
void OnConnectionError() {
if (quit_closure_)
quit_closure_.Run();
}
mojo::Binding<mojom::Recorder> binding_;
std::string events_;
std::string metadata_;
base::Closure quit_closure_;
};
class TraceEventAgentTest : public testing::Test {
public:
void TearDown() override {
base::trace_event::TraceLog::GetInstance()->SetDisabled();
recorder_.reset();
}
void StartTracing(const std::string& categories) {
TraceEventAgent::GetInstance()->StartTracing(
base::trace_event::TraceConfig(categories, "").ToString(),
base::TimeTicks::Now(),
base::BindRepeating([](bool success) { EXPECT_TRUE(success); }));
}
void StopAndFlush(base::Closure quit_closure) {
mojom::RecorderPtr recorder_ptr;
recorder_.reset(new MockRecorder(MakeRequest(&recorder_ptr)));
recorder_->set_quit_closure(quit_closure);
TraceEventAgent::GetInstance()->StopAndFlush(std::move(recorder_ptr));
}
void AddMetadataGeneratorFunction(
TraceEventAgent::MetadataGeneratorFunction generator) {
TraceEventAgent::GetInstance()->AddMetadataGeneratorFunction(generator);
}
MockRecorder* recorder() const { return recorder_.get(); }
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<MockRecorder> recorder_;
};
TEST_F(TraceEventAgentTest, StartTracing) {
EXPECT_FALSE(base::trace_event::TraceLog::GetInstance()->IsEnabled());
base::RunLoop run_loop;
StartTracing("*");
EXPECT_TRUE(base::trace_event::TraceLog::GetInstance()->IsEnabled());
StopAndFlush(run_loop.QuitClosure());
run_loop.Run();
}
TEST_F(TraceEventAgentTest, StopAndFlushEvents) {
EXPECT_FALSE(base::trace_event::TraceLog::GetInstance()->IsEnabled());
base::RunLoop run_loop;
StartTracing(kTestCategory);
TRACE_EVENT_INSTANT0(kTestCategory, "event1", TRACE_EVENT_SCOPE_THREAD);
TRACE_EVENT_INSTANT0(kTestCategory, "event2", TRACE_EVENT_SCOPE_THREAD);
StopAndFlush(run_loop.QuitClosure());
run_loop.Run();
auto* mock_recorder = recorder();
EXPECT_EQ("event1,event2", mock_recorder->events());
EXPECT_EQ("", mock_recorder->metadata());
EXPECT_FALSE(base::trace_event::TraceLog::GetInstance()->IsEnabled());
}
TEST_F(TraceEventAgentTest, StopAndFlushMetadata) {
EXPECT_FALSE(base::trace_event::TraceLog::GetInstance()->IsEnabled());
base::RunLoop run_loop;
AddMetadataGeneratorFunction(base::BindRepeating([] {
std::unique_ptr<base::DictionaryValue> metadata_dict(
new base::DictionaryValue());
metadata_dict->SetString(kTestMetadataKey, "test metadata");
return metadata_dict;
}));
StartTracing(kTestCategory);
StopAndFlush(run_loop.QuitClosure());
run_loop.Run();
auto* mock_recorder = recorder();
EXPECT_EQ("", mock_recorder->events());
EXPECT_EQ("test metadata", mock_recorder->metadata());
EXPECT_FALSE(base::trace_event::TraceLog::GetInstance()->IsEnabled());
}
} // namespace tracing