/*
|
* 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/tracing/core/trace_packet.h"
|
|
#include <string>
|
|
#include "gtest/gtest.h"
|
|
#include "perfetto/trace/trace.pb.h"
|
#include "perfetto/trace/trace_packet.pb.h"
|
#include "perfetto/trace/trusted_packet.pb.h"
|
|
namespace perfetto {
|
namespace {
|
|
static_assert(TracePacket::kPacketFieldNumber ==
|
protos::Trace::kPacketFieldNumber,
|
"packet field id mismatch");
|
|
static_assert(protos::TracePacket::kTrustedUidFieldNumber ==
|
protos::TrustedPacket::kTrustedUidFieldNumber,
|
"trusted_uid field id mismatch");
|
|
static_assert(protos::TracePacket::kTraceConfigFieldNumber ==
|
protos::TrustedPacket::kTraceConfigFieldNumber,
|
"trace_config field id mismatch");
|
|
static_assert(protos::TracePacket::kTraceStatsFieldNumber ==
|
protos::TrustedPacket::kTraceStatsFieldNumber,
|
"trace_stats field id mismatch");
|
|
static_assert(protos::TracePacket::kClockSnapshotFieldNumber ==
|
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(tp.Decode(&decoded_packet));
|
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(tp.Decode(&decoded_packet));
|
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(tp.Decode(&decoded_packet));
|
}
|
|
// 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
|