blob: beb9bca076740773379f23a0812ada6de78df816 [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/coordinator.h"
#include <memory>
#include "base/run_loop.h"
#include "services/tracing/coordinator_test_util.h"
#include "services/tracing/test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace tracing {
class CoordinatorTest : public testing::Test, public CoordinatorTestUtil {
public:
void SetUp() override {
CoordinatorTestUtil::SetUp();
coordinator_ = std::make_unique<Coordinator>(agent_registry(),
base::RepeatingClosure());
coordinator_->FinishedReceivingRunningPIDs();
}
void TearDown() override { CoordinatorTestUtil::TearDown(); }
};
TEST_F(CoordinatorTest, StartTracingSimple) {
base::RunLoop run_loop;
auto* agent = AddArrayAgent();
StartTracing("*", true);
run_loop.RunUntilIdle();
// The agent should have received exactly one call from the coordinator.
EXPECT_EQ(1u, agent->call_stat().size());
EXPECT_EQ("StartTracing", agent->call_stat()[0]);
}
TEST_F(CoordinatorTest, StartTracingTwoAgents) {
base::RunLoop run_loop;
auto* agent1 = AddArrayAgent();
StartTracing("*", true);
auto* agent2 = AddStringAgent();
run_loop.RunUntilIdle();
// Each agent should have received exactly one call from the coordinator.
EXPECT_EQ(1u, agent1->call_stat().size());
EXPECT_EQ("StartTracing", agent1->call_stat()[0]);
EXPECT_EQ(1u, agent2->call_stat().size());
EXPECT_EQ("StartTracing", agent2->call_stat()[0]);
}
TEST_F(CoordinatorTest, StartTracingWithProcessFilter) {
base::RunLoop run_loop1;
auto* agent1 = AddArrayAgent(static_cast<base::ProcessId>(1));
auto* agent2 = AddArrayAgent(static_cast<base::ProcessId>(2));
StartTracing("{\"included_process_ids\":[2,4]}", true);
run_loop1.RunUntilIdle();
base::RunLoop run_loop2;
auto* agent3 = AddArrayAgent(static_cast<base::ProcessId>(3));
auto* agent4 = AddArrayAgent(static_cast<base::ProcessId>(4));
StartTracing("{\"included_process_ids\":[4,6]}", true);
run_loop2.RunUntilIdle();
base::RunLoop run_loop3;
auto* agent5 = AddArrayAgent(static_cast<base::ProcessId>(5));
auto* agent6 = AddArrayAgent(static_cast<base::ProcessId>(6));
run_loop3.RunUntilIdle();
// StartTracing should only be received by agents 2, 4, and 6.
EXPECT_EQ(0u, agent1->call_stat().size());
EXPECT_EQ(1u, agent2->call_stat().size());
EXPECT_EQ("StartTracing", agent2->call_stat()[0]);
EXPECT_EQ(0u, agent3->call_stat().size());
EXPECT_EQ(1u, agent4->call_stat().size());
EXPECT_EQ("StartTracing", agent4->call_stat()[0]);
EXPECT_EQ(0u, agent5->call_stat().size());
EXPECT_EQ(1u, agent6->call_stat().size());
EXPECT_EQ("StartTracing", agent6->call_stat()[0]);
}
TEST_F(CoordinatorTest, StartTracingWithDifferentConfigs) {
base::RunLoop run_loop;
auto* agent = AddArrayAgent();
StartTracing("config 1", true);
// The 2nd |StartTracing| should return false.
StartTracing("config 2", false);
run_loop.RunUntilIdle();
// The agent should have received exactly one call from the coordinator
// because the 2nd |StartTracing| was aborted.
EXPECT_EQ(1u, agent->call_stat().size());
EXPECT_EQ("StartTracing", agent->call_stat()[0]);
}
TEST_F(CoordinatorTest, StartTracingWithSameConfigs) {
base::RunLoop run_loop;
auto* agent = AddArrayAgent();
StartTracing("config", true);
// The 2nd |StartTracing| should return true when we are not trying to change
// the config.
StartTracing("config", true);
run_loop.RunUntilIdle();
// The agent should have received exactly one call from the coordinator
// because the 2nd |StartTracing| was a no-op.
EXPECT_EQ(1u, agent->call_stat().size());
EXPECT_EQ("StartTracing", agent->call_stat()[0]);
}
TEST_F(CoordinatorTest, StopAndFlushObjectAgent) {
auto* agent = AddObjectAgent();
agent->data_.push_back("\"content\":{\"a\":1}");
agent->data_.push_back("\"name\":\"etw\"");
StartTracing("config", true);
std::string output = StopAndFlush();
EXPECT_EQ("{\"systemTraceEvents\":{\"content\":{\"a\":1},\"name\":\"etw\"}}",
output);
// Each agent should have received exactly two calls.
EXPECT_EQ(2u, agent->call_stat().size());
EXPECT_EQ("StartTracing", agent->call_stat()[0]);
EXPECT_EQ("StopAndFlush", agent->call_stat()[1]);
}
TEST_F(CoordinatorTest, StopAndFlushTwoArrayAgents) {
auto* agent1 = AddArrayAgent();
agent1->data_.push_back("e1");
agent1->data_.push_back("e2");
auto* agent2 = AddArrayAgent();
agent2->data_.push_back("e3");
agent2->data_.push_back("e4");
StartTracing("config", true);
std::string output = StopAndFlush();
// |output| should be of the form {"traceEvents":[ei,ej,ek,el]}, where
// ei,ej,ek,el is a permutation of e1,e2,e3,e4 such that e1 is before e2 and
// e3 is before e4 since e1 and 2 come from the same agent and their order
// should be preserved and, similarly, the order of e3 and e4 should be
// preserved, too.
EXPECT_TRUE(output == "{\"traceEvents\":[e1,e2,e3,e4]}" ||
output == "{\"traceEvents\":[e1,e3,e2,e4]}" ||
output == "{\"traceEvents\":[e1,e3,e4,e2]}" ||
output == "{\"traceEvents\":[e3,e1,e2,e4]}" ||
output == "{\"traceEvents\":[e3,e1,e4,e2]}" ||
output == "{\"traceEvents\":[e3,e4,e1,e2]}");
// Each agent should have received exactly two calls.
EXPECT_EQ(2u, agent1->call_stat().size());
EXPECT_EQ("StartTracing", agent1->call_stat()[0]);
EXPECT_EQ("StopAndFlush", agent1->call_stat()[1]);
EXPECT_EQ(2u, agent2->call_stat().size());
EXPECT_EQ("StartTracing", agent2->call_stat()[0]);
EXPECT_EQ("StopAndFlush", agent2->call_stat()[1]);
}
TEST_F(CoordinatorTest, StopAndFlushDifferentTypeAgents) {
auto* agent1 = AddArrayAgent();
agent1->data_.push_back("e1");
agent1->data_.push_back("e2");
auto* agent2 = AddStringAgent();
agent2->data_.push_back("e3");
agent2->data_.push_back("e4");
StartTracing("config", true);
std::string output = StopAndFlush();
EXPECT_TRUE(output == "{\"traceEvents\":[e1,e2],\"power\":\"e3e4\"}" ||
output == "{\"power\":\"e3e4\",\"traceEvents\":[e1,e2]}");
// Each agent should have received exactly two calls.
EXPECT_EQ(2u, agent1->call_stat().size());
EXPECT_EQ("StartTracing", agent1->call_stat()[0]);
EXPECT_EQ("StopAndFlush", agent1->call_stat()[1]);
EXPECT_EQ(2u, agent2->call_stat().size());
EXPECT_EQ("StartTracing", agent2->call_stat()[0]);
EXPECT_EQ("StopAndFlush", agent2->call_stat()[1]);
}
TEST_F(CoordinatorTest, StopAndFlushWithMetadata) {
auto* agent = AddArrayAgent();
agent->data_.push_back("event");
agent->metadata_.SetString("key", "value");
StartTracing("config", true);
std::string output = StopAndFlush();
// Metadata is written at after trace data.
EXPECT_EQ("{\"traceEvents\":[event],\"metadata\":{\"key\":\"value\"}}",
output);
EXPECT_EQ(2u, agent->call_stat().size());
EXPECT_EQ("StartTracing", agent->call_stat()[0]);
EXPECT_EQ("StopAndFlush", agent->call_stat()[1]);
}
TEST_F(CoordinatorTest, IsTracing) {
base::RunLoop run_loop;
AddArrayAgent();
StartTracing("config", true);
IsTracing(true);
run_loop.RunUntilIdle();
}
TEST_F(CoordinatorTest, IsNotTracing) {
base::RunLoop run_loop;
IsTracing(false);
run_loop.RunUntilIdle();
}
TEST_F(CoordinatorTest, RequestBufferUsage) {
auto* agent1 = AddArrayAgent();
agent1->trace_log_status_.event_capacity = 4;
agent1->trace_log_status_.event_count = 1;
RequestBufferUsage(0.25, 1);
base::RunLoop().RunUntilIdle();
CheckDisconnectClosures(1);
auto* agent2 = AddArrayAgent();
agent2->trace_log_status_.event_capacity = 8;
agent2->trace_log_status_.event_count = 1;
// The buffer usage of |agent2| is less than the buffer usage of |agent1| and
// so the total buffer usage, i.e 0.25, does not change. But the approximate
// count will be increased from 1 to 2.
RequestBufferUsage(0.25, 2);
base::RunLoop().RunUntilIdle();
CheckDisconnectClosures(2);
base::RunLoop run_loop3;
auto* agent3 = AddArrayAgent();
agent3->trace_log_status_.event_capacity = 8;
agent3->trace_log_status_.event_count = 4;
// |agent3| has the worst buffer usage of 0.5.
RequestBufferUsage(0.5, 6);
base::RunLoop().RunUntilIdle();
CheckDisconnectClosures(3);
// At the end |agent1| receives 3 calls, |agent2| receives 2 calls, and
// |agent3| receives 1 call.
EXPECT_EQ(3u, agent1->call_stat().size());
EXPECT_EQ(2u, agent2->call_stat().size());
EXPECT_EQ(1u, agent3->call_stat().size());
}
TEST_F(CoordinatorTest, LateAgents) {
auto* agent1 = AddArrayAgent();
StartTracing("config", true);
StopAndFlush();
base::RunLoop run_loop;
auto* agent2 = AddArrayAgent();
agent2->data_.push_back("discarded data");
run_loop.RunUntilIdle();
EXPECT_EQ(2u, agent1->call_stat().size());
EXPECT_EQ("StartTracing", agent1->call_stat()[0]);
EXPECT_EQ("StopAndFlush", agent1->call_stat()[1]);
// The second agent that registers after the end of a tracing session should
// receive a StopAndFlush message.
EXPECT_EQ(1u, agent2->call_stat().size());
EXPECT_EQ("StopAndFlush", agent2->call_stat()[0]);
}
TEST_F(CoordinatorTest, WaitForSpecificPIDs) {
coordinator_->AddExpectedPID(42);
coordinator_->AddExpectedPID(4242);
auto* agent1 = AddArrayAgent(42);
StartTracing("config", true);
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(tracing_begin_callback_received());
auto* agent2 = AddArrayAgent(4242);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(tracing_begin_callback_received());
StopAndFlush();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2u, agent1->call_stat().size());
EXPECT_EQ("StartTracing", agent1->call_stat()[0]);
EXPECT_EQ("StopAndFlush", agent1->call_stat()[1]);
EXPECT_EQ(2u, agent2->call_stat().size());
EXPECT_EQ("StartTracing", agent2->call_stat()[0]);
EXPECT_EQ("StopAndFlush", agent2->call_stat()[1]);
}
} // namespace tracing