// Copyright 2016 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 "base/trace_event/blame_context.h" #include "base/json/json_writer.h" #include "base/message_loop/message_loop.h" #include "base/test/trace_event_analyzer.h" #include "base/trace_event/trace_event_argument.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { namespace trace_event { namespace { const char kTestBlameContextCategory[] = "test"; const char kDisabledTestBlameContextCategory[] = "disabled-by-default-test"; const char kTestBlameContextName[] = "TestBlameContext"; const char kTestBlameContextType[] = "TestBlameContextType"; const char kTestBlameContextScope[] = "TestBlameContextScope"; class TestBlameContext : public BlameContext { public: explicit TestBlameContext(int id) : BlameContext(kTestBlameContextCategory, kTestBlameContextName, kTestBlameContextType, kTestBlameContextScope, id, nullptr) {} TestBlameContext(int id, const TestBlameContext& parent) : BlameContext(kTestBlameContextCategory, kTestBlameContextName, kTestBlameContextType, kTestBlameContextScope, id, &parent) {} protected: void AsValueInto(trace_event::TracedValue* state) override { BlameContext::AsValueInto(state); state->SetBoolean("crossStreams", false); } }; class DisabledTestBlameContext : public BlameContext { public: explicit DisabledTestBlameContext(int id) : BlameContext(kDisabledTestBlameContextCategory, kTestBlameContextName, kTestBlameContextType, kTestBlameContextScope, id, nullptr) {} }; class BlameContextTest : public testing::Test { protected: MessageLoop loop_; }; TEST_F(BlameContextTest, EnterAndLeave) { using trace_analyzer::Query; trace_analyzer::Start("*"); { TestBlameContext blame_context(0x1234); blame_context.Initialize(); blame_context.Enter(); blame_context.Leave(); } auto analyzer = trace_analyzer::Stop(); trace_analyzer::TraceEventVector events; Query q = Query::EventPhaseIs(TRACE_EVENT_PHASE_ENTER_CONTEXT) || Query::EventPhaseIs(TRACE_EVENT_PHASE_LEAVE_CONTEXT); analyzer->FindEvents(q, &events); EXPECT_EQ(2u, events.size()); EXPECT_EQ(TRACE_EVENT_PHASE_ENTER_CONTEXT, events[0]->phase); EXPECT_EQ(kTestBlameContextCategory, events[0]->category); EXPECT_EQ(kTestBlameContextName, events[0]->name); EXPECT_EQ("0x1234", events[0]->id); EXPECT_EQ(TRACE_EVENT_PHASE_LEAVE_CONTEXT, events[1]->phase); EXPECT_EQ(kTestBlameContextCategory, events[1]->category); EXPECT_EQ(kTestBlameContextName, events[1]->name); EXPECT_EQ("0x1234", events[1]->id); } TEST_F(BlameContextTest, DifferentCategories) { // Ensure there is no cross talk between blame contexts from different // categories. using trace_analyzer::Query; trace_analyzer::Start("*"); { TestBlameContext blame_context(0x1234); DisabledTestBlameContext disabled_blame_context(0x5678); blame_context.Initialize(); blame_context.Enter(); blame_context.Leave(); disabled_blame_context.Initialize(); disabled_blame_context.Enter(); disabled_blame_context.Leave(); } auto analyzer = trace_analyzer::Stop(); trace_analyzer::TraceEventVector events; Query q = Query::EventPhaseIs(TRACE_EVENT_PHASE_ENTER_CONTEXT) || Query::EventPhaseIs(TRACE_EVENT_PHASE_LEAVE_CONTEXT); analyzer->FindEvents(q, &events); // None of the events from the disabled-by-default category should show up. EXPECT_EQ(2u, events.size()); EXPECT_EQ(TRACE_EVENT_PHASE_ENTER_CONTEXT, events[0]->phase); EXPECT_EQ(kTestBlameContextCategory, events[0]->category); EXPECT_EQ(kTestBlameContextName, events[0]->name); EXPECT_EQ("0x1234", events[0]->id); EXPECT_EQ(TRACE_EVENT_PHASE_LEAVE_CONTEXT, events[1]->phase); EXPECT_EQ(kTestBlameContextCategory, events[1]->category); EXPECT_EQ(kTestBlameContextName, events[1]->name); EXPECT_EQ("0x1234", events[1]->id); } TEST_F(BlameContextTest, TakeSnapshot) { using trace_analyzer::Query; trace_analyzer::Start("*"); { TestBlameContext parent_blame_context(0x5678); TestBlameContext blame_context(0x1234, parent_blame_context); parent_blame_context.Initialize(); blame_context.Initialize(); blame_context.TakeSnapshot(); } auto analyzer = trace_analyzer::Stop(); trace_analyzer::TraceEventVector events; Query q = Query::EventPhaseIs(TRACE_EVENT_PHASE_SNAPSHOT_OBJECT); analyzer->FindEvents(q, &events); // We should have 3 snapshots: one for both calls to Initialize() and one from // the explicit call to TakeSnapshot(). EXPECT_EQ(3u, events.size()); EXPECT_EQ(kTestBlameContextCategory, events[0]->category); EXPECT_EQ(kTestBlameContextType, events[0]->name); EXPECT_EQ("0x5678", events[0]->id); EXPECT_TRUE(events[0]->HasArg("snapshot")); EXPECT_EQ(kTestBlameContextCategory, events[1]->category); EXPECT_EQ(kTestBlameContextType, events[1]->name); EXPECT_EQ("0x1234", events[1]->id); EXPECT_TRUE(events[0]->HasArg("snapshot")); EXPECT_EQ(kTestBlameContextCategory, events[2]->category); EXPECT_EQ(kTestBlameContextType, events[2]->name); EXPECT_EQ("0x1234", events[2]->id); EXPECT_TRUE(events[0]->HasArg("snapshot")); const char kExpectedSnapshotJson[] = "{" "\"crossStreams\":false," "\"parent\":{" "\"id_ref\":\"0x5678\"," "\"scope\":\"TestBlameContextScope\"" "}" "}"; std::string snapshot_json; JSONWriter::Write(*events[2]->GetKnownArgAsValue("snapshot"), &snapshot_json); EXPECT_EQ(kExpectedSnapshotJson, snapshot_json); } } // namepace } // namespace trace_event } // namespace base