blob: 0469ae8570165705f094353d51ca29f74aac739b [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "perfetto/ext/tracing/core/trace_packet.h"
#include <string>
#include "protos/perfetto/trace/trace.pb.h"
#include "protos/perfetto/trace/trace_packet.pb.h"
#include "protos/perfetto/trace/trusted_packet.pb.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
namespace {
static_assert(static_cast<int>(TracePacket::kPacketFieldNumber) ==
static_cast<int>(protos::Trace::kPacketFieldNumber),
"packet field id mismatch");
static_assert(
static_cast<int>(protos::TracePacket::kTrustedUidFieldNumber) ==
static_cast<int>(protos::TrustedPacket::kTrustedUidFieldNumber),
"trusted_uid field id mismatch");
static_assert(
static_cast<int>(protos::TracePacket::kTraceConfigFieldNumber) ==
static_cast<int>(protos::TrustedPacket::kTraceConfigFieldNumber),
"trace_config field id mismatch");
static_assert(
static_cast<int>(protos::TracePacket::kTraceStatsFieldNumber) ==
static_cast<int>(protos::TrustedPacket::kTraceStatsFieldNumber),
"trace_stats field id mismatch");
static_assert(
static_cast<int>(protos::TracePacket::kClockSnapshotFieldNumber) ==
static_cast<int>(protos::TrustedPacket::kClockSnapshotFieldNumber),
"clock_snapshot field id mismatch");
TEST(TracePacketTest, Simple) {
protos::TracePacket proto;
proto.mutable_for_testing()->set_str("string field");
std::string ser_buf = proto.SerializeAsString();
TracePacket tp;
tp.AddSlice(ser_buf.data(), ser_buf.size());
auto slice = tp.slices().begin();
ASSERT_NE(tp.slices().end(), slice);
ASSERT_EQ(ser_buf.data(), slice->start);
ASSERT_EQ(ser_buf.size(), slice->size);
ASSERT_EQ(tp.slices().end(), ++slice);
protos::TracePacket decoded_packet;
ASSERT_TRUE(decoded_packet.ParseFromString(tp.GetRawBytesForTesting()));
ASSERT_EQ(proto.for_testing().str(), decoded_packet.for_testing().str());
}
TEST(TracePacketTest, Sliced) {
protos::TracePacket proto;
proto.mutable_for_testing()->set_str(
"this is an arbitrarily long string ........................");
std::string ser_buf = proto.SerializeAsString();
TracePacket tp;
tp.AddSlice({ser_buf.data(), 3});
tp.AddSlice({ser_buf.data() + 3, 5});
tp.AddSlice({ser_buf.data() + 3 + 5, ser_buf.size() - 3 - 5});
ASSERT_EQ(ser_buf.size(), tp.size());
auto slice = tp.slices().begin();
ASSERT_NE(tp.slices().end(), slice);
ASSERT_EQ(ser_buf.data(), slice->start);
ASSERT_EQ(3u, slice->size);
ASSERT_NE(tp.slices().end(), ++slice);
ASSERT_EQ(ser_buf.data() + 3, slice->start);
ASSERT_EQ(5u, slice->size);
ASSERT_NE(tp.slices().end(), ++slice);
ASSERT_EQ(ser_buf.data() + 3 + 5, slice->start);
ASSERT_EQ(ser_buf.size() - 3 - 5, slice->size);
ASSERT_EQ(tp.slices().end(), ++slice);
protos::TracePacket decoded_packet;
ASSERT_TRUE(decoded_packet.ParseFromString(tp.GetRawBytesForTesting()));
ASSERT_EQ(proto.for_testing().str(), decoded_packet.for_testing().str());
}
TEST(TracePacketTest, Corrupted) {
protos::TracePacket proto;
proto.mutable_for_testing()->set_str("string field");
std::string ser_buf = proto.SerializeAsString();
TracePacket tp;
tp.AddSlice({ser_buf.data(), ser_buf.size() - 2}); // corrupted.
protos::TracePacket decoded_packet;
ASSERT_FALSE(decoded_packet.ParseFromString(tp.GetRawBytesForTesting()));
}
// Tests that the GetProtoPreamble() logic returns a valid preamble that allows
// to encode a TracePacket as a field of the root trace.proto message.
TEST(TracePacketTest, GetProtoPreamble) {
char* preamble;
size_t preamble_size;
// Test empty packet.
TracePacket tp;
std::tie(preamble, preamble_size) = tp.GetProtoPreamble();
ASSERT_EQ(2u, preamble_size);
ASSERT_EQ(0, preamble[1]);
// Test packet with one slice.
protos::TracePacket tp_proto;
char payload[257];
for (size_t i = 0; i < sizeof(payload) - 1; i++)
payload[i] = 'a' + (i % 16);
payload[sizeof(payload) - 1] = '\0';
tp_proto.mutable_for_testing()->set_str(payload);
std::string ser_buf = tp_proto.SerializeAsString();
tp.AddSlice({ser_buf.data(), ser_buf.size()});
std::tie(preamble, preamble_size) = tp.GetProtoPreamble();
ASSERT_EQ(3u, preamble_size);
// Verify that the content is actually parsable using libprotobuf.
char buf[512];
memcpy(buf, preamble, preamble_size);
ASSERT_EQ(1u, tp.slices().size());
memcpy(&buf[preamble_size], tp.slices()[0].start, tp.slices()[0].size);
protos::Trace trace;
ASSERT_TRUE(
trace.ParseFromArray(buf, static_cast<int>(preamble_size + tp.size())));
ASSERT_EQ(1, trace.packet_size());
ASSERT_EQ(payload, trace.packet(0).for_testing().str());
}
TEST(TracePacketTest, MoveOperators) {
char buf1[5]{};
char buf2[7]{};
TracePacket tp;
tp.AddSlice(buf1, sizeof(buf1));
tp.AddSlice(buf2, sizeof(buf2));
tp.AddSlice(Slice::Allocate(11));
tp.AddSlice(Slice(std::unique_ptr<std::string>(new std::string("foobar"))));
TracePacket moved_tp(std::move(tp));
ASSERT_EQ(0u, tp.size());
ASSERT_TRUE(tp.slices().empty());
ASSERT_EQ(4u, moved_tp.slices().size());
ASSERT_EQ(5u + 7u + 11u + 6u, moved_tp.size());
TracePacket moved_tp_2;
moved_tp_2 = std::move(moved_tp);
ASSERT_EQ(0u, moved_tp.size());
ASSERT_TRUE(moved_tp.slices().empty());
ASSERT_EQ(4u, moved_tp_2.slices().size());
ASSERT_EQ(5u + 7u + 11u + 6u, moved_tp_2.size());
}
} // namespace
} // namespace perfetto