[go: nahoru, domu]

blob: b93a659da5e566713123be9a728296ce960c8348 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// 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/perfetto/trace_packet_tokenizer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_packet.h"
#include "third_party/perfetto/protos/perfetto/trace/trace.pb.h"
#include "third_party/perfetto/protos/perfetto/trace/trace_packet.pb.h"
#include <list>
namespace tracing {
namespace {
constexpr char kTestString[] = "This little packet went to the market";
class TracePacketTokenizerTest : public testing::Test {
protected:
// Parse a trace chunk using an indirect memory allocation so ASAN can detect
// any out-of-bounds reads.
std::vector<perfetto::TracePacket> ParseChunk(const uint8_t* data,
size_t size) {
input_chunks_.emplace_back(data, data + size);
auto& it = input_chunks_.back();
return tokenizer_.Parse(it.data(), it.size());
}
void Reset() {
input_chunks_.clear();
tokenizer_ = TracePacketTokenizer();
}
TracePacketTokenizer& tokenizer() { return tokenizer_; }
private:
std::list<std::vector<uint8_t>> input_chunks_;
TracePacketTokenizer tokenizer_;
};
TEST_F(TracePacketTokenizerTest, Basic) {
perfetto::protos::Trace trace;
auto* packet = trace.add_packet();
packet->mutable_for_testing()->set_str(kTestString);
auto packet_data = trace.SerializeAsString();
auto packets = ParseChunk(
reinterpret_cast<const uint8_t*>(packet_data.data()), packet_data.size());
EXPECT_EQ(1u, packets.size());
perfetto::protos::TracePacket parsed_packet;
EXPECT_TRUE(
parsed_packet.ParseFromString(packets[0].GetRawBytesForTesting()));
EXPECT_EQ(kTestString, parsed_packet.for_testing().str());
EXPECT_FALSE(tokenizer().has_more());
}
TEST_F(TracePacketTokenizerTest, PartialParse) {
perfetto::protos::Trace trace;
auto* packet = trace.add_packet();
packet->mutable_for_testing()->set_str(kTestString);
auto packet_data = trace.SerializeAsString();
auto packets =
ParseChunk(reinterpret_cast<const uint8_t*>(packet_data.data()),
packet_data.size() / 2);
EXPECT_TRUE(packets.empty());
EXPECT_TRUE(tokenizer().has_more());
packets = ParseChunk(reinterpret_cast<const uint8_t*>(packet_data.data() +
packet_data.size() / 2),
packet_data.size() / 2);
EXPECT_EQ(1u, packets.size());
perfetto::protos::TracePacket parsed_packet;
EXPECT_TRUE(
parsed_packet.ParseFromString(packets[0].GetRawBytesForTesting()));
EXPECT_EQ(kTestString, parsed_packet.for_testing().str());
EXPECT_FALSE(tokenizer().has_more());
}
TEST_F(TracePacketTokenizerTest, MultiplePackets) {
constexpr size_t kPacketCount = 32;
perfetto::protos::Trace trace;
for (size_t i = 0; i < kPacketCount; i++) {
auto* packet = trace.add_packet();
packet->set_timestamp(i);
packet->mutable_for_testing()->set_str(kTestString);
}
auto packet_data = trace.SerializeAsString();
auto packets = ParseChunk(
reinterpret_cast<const uint8_t*>(packet_data.data()), packet_data.size());
EXPECT_EQ(kPacketCount, packets.size());
for (size_t i = 0; i < kPacketCount; i++) {
perfetto::protos::TracePacket parsed_packet;
EXPECT_TRUE(
parsed_packet.ParseFromString(packets[i].GetRawBytesForTesting()));
EXPECT_EQ(i, parsed_packet.timestamp());
EXPECT_EQ(kTestString, parsed_packet.for_testing().str());
}
EXPECT_FALSE(tokenizer().has_more());
}
TEST_F(TracePacketTokenizerTest, Fragmentation) {
constexpr size_t kPacketCount = 17;
perfetto::protos::Trace trace;
for (size_t i = 0; i < kPacketCount; i++) {
auto* packet = trace.add_packet();
packet->set_timestamp(i + 1);
packet->mutable_for_testing()->set_str(kTestString);
}
auto packet_data = trace.SerializeAsString();
for (size_t chunk_size = 1; chunk_size < packet_data.size(); chunk_size++) {
size_t packet_count = 0;
for (size_t offset = 0; offset < packet_data.size(); offset += chunk_size) {
const auto* chunk_start =
reinterpret_cast<const uint8_t*>(packet_data.data()) + offset;
const auto* chunk_end =
std::min(chunk_start + chunk_size,
reinterpret_cast<const uint8_t*>(&*packet_data.end()));
auto packets = ParseChunk(chunk_start, chunk_end - chunk_start);
if (packets.empty())
continue;
packet_count += packets.size();
for (auto& packet : packets) {
perfetto::protos::TracePacket parsed_packet;
EXPECT_TRUE(
parsed_packet.ParseFromString(packet.GetRawBytesForTesting()));
EXPECT_GT(parsed_packet.timestamp(), 0u);
EXPECT_EQ(kTestString, parsed_packet.for_testing().str());
}
}
EXPECT_EQ(kPacketCount, packet_count);
EXPECT_FALSE(tokenizer().has_more());
Reset();
}
}
} // namespace
} // namespace tracing