blob: d20885fe1dbad049bc8447bbf700081074cb3144 [file] [log] [blame]
/*
* Copyright (C) 2022 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/internal/interceptor_trace_writer.h"
#include "perfetto/tracing/interceptor.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
namespace internal {
namespace {
using ::testing::AllOf;
using ::testing::Field;
using ::testing::HasSubstr;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::IsNull;
using ::testing::MockFunction;
using ::testing::Not;
using ::testing::NotNull;
constexpr uint32_t kInstanceIndex = 42;
} // namespace
class InterceptorTraceWriterTest : public testing::Test {
protected:
using TracePacketCallbackArgs = InterceptorBase::TracePacketCallbackArgs;
using ThreadLocalState = InterceptorBase::ThreadLocalState;
using MockTracePacketCallback = MockFunction<void(TracePacketCallbackArgs)>;
InterceptorTraceWriterTest()
: tls_ptr_(new ThreadLocalState()),
tw_(std::unique_ptr<ThreadLocalState>(tls_ptr_),
TracePacketCallback,
&dss_,
kInstanceIndex) {}
void SetUp() override {
static_trace_packet_callback_ = &trace_packet_callback_;
}
void TearDown() override { static_trace_packet_callback_ = nullptr; }
static void TracePacketCallback(
InterceptorBase::TracePacketCallbackArgs args) {
ASSERT_THAT(static_trace_packet_callback_, NotNull());
static_trace_packet_callback_->Call(args);
}
MockTracePacketCallback trace_packet_callback_;
static MockTracePacketCallback* static_trace_packet_callback_;
ThreadLocalState* tls_ptr_;
DataSourceStaticState dss_;
InterceptorTraceWriter tw_;
};
InterceptorTraceWriterTest::MockTracePacketCallback*
InterceptorTraceWriterTest::static_trace_packet_callback_;
TEST_F(InterceptorTraceWriterTest, TracePacketCallbackParams) {
EXPECT_CALL(trace_packet_callback_,
Call(AllOf(Field(&TracePacketCallbackArgs::instance_index,
kInstanceIndex),
Field(&TracePacketCallbackArgs::static_state, &dss_),
Field(&TracePacketCallbackArgs::tls, tls_ptr_))))
.Times(1);
tw_.NewTracePacket();
tw_.Flush();
}
TEST_F(InterceptorTraceWriterTest, NewTracePacketAutomaticallyAddedFields) {
std::string first_packet;
std::string second_packet;
EXPECT_CALL(trace_packet_callback_, Call)
.WillOnce(Invoke([&](TracePacketCallbackArgs args) {
first_packet = args.packet_data.ToStdString();
}))
.WillOnce(Invoke([&](TracePacketCallbackArgs args) {
second_packet = args.packet_data.ToStdString();
}));
tw_.NewTracePacket();
tw_.NewTracePacket();
tw_.Flush();
protos::pbzero::TracePacket::Decoder first(first_packet);
protos::pbzero::TracePacket::Decoder second(second_packet);
EXPECT_TRUE(first.has_trusted_packet_sequence_id());
EXPECT_TRUE(second.has_trusted_packet_sequence_id());
EXPECT_EQ(first.trusted_packet_sequence_id(),
second.trusted_packet_sequence_id());
}
TEST_F(InterceptorTraceWriterTest, NewTracePacketLargePacket) {
size_t first_packet_size;
size_t second_packet_size;
EXPECT_CALL(trace_packet_callback_, Call)
.WillOnce(Invoke([&](TracePacketCallbackArgs args) {
first_packet_size = args.packet_data.size;
}))
.WillOnce(Invoke([&](TracePacketCallbackArgs args) {
second_packet_size = args.packet_data.size;
}));
tw_.NewTracePacket();
{
auto msg = tw_.NewTracePacket();
std::vector<uint8_t> large(20000u, 0);
msg->AppendRawProtoBytes(large.data(), large.size());
}
tw_.Flush();
EXPECT_EQ(second_packet_size, first_packet_size + 20000u);
}
TEST_F(InterceptorTraceWriterTest, NewTracePacketTakeWriterLargePacket) {
size_t first_packet_size;
size_t second_packet_size;
EXPECT_CALL(trace_packet_callback_, Call)
.WillOnce(Invoke([&](TracePacketCallbackArgs args) {
first_packet_size = args.packet_data.size;
}))
.WillOnce(Invoke([&](TracePacketCallbackArgs args) {
second_packet_size = args.packet_data.size;
}));
tw_.NewTracePacket();
tw_.FinishTracePacket();
protozero::ScatteredStreamWriter* writer =
tw_.NewTracePacket().TakeStreamWriter();
std::vector<uint8_t> large(20000u, 0);
writer->WriteBytes(large.data(), large.size());
tw_.FinishTracePacket();
tw_.Flush();
EXPECT_EQ(second_packet_size, first_packet_size + 20000u);
}
TEST_F(InterceptorTraceWriterTest, MixManualTakeAndMessage) {
std::string content1 = "AAAAA";
std::string content2 = "BBBBB";
std::string content3 = "CCCCC";
EXPECT_CALL(trace_packet_callback_, Call)
.WillOnce(Invoke([&](TracePacketCallbackArgs args) {
std::string data = args.packet_data.ToStdString();
EXPECT_THAT(data, HasSubstr(content1));
EXPECT_THAT(data, Not(HasSubstr(content2)));
EXPECT_THAT(data, Not(HasSubstr(content3)));
}))
.WillOnce(Invoke([&](TracePacketCallbackArgs args) {
std::string data = args.packet_data.ToStdString();
EXPECT_THAT(data, Not(HasSubstr(content1)));
EXPECT_THAT(data, HasSubstr(content2));
EXPECT_THAT(data, Not(HasSubstr(content3)));
}))
.WillOnce(Invoke([&](TracePacketCallbackArgs args) {
std::string data = args.packet_data.ToStdString();
EXPECT_THAT(data, Not(HasSubstr(content1)));
EXPECT_THAT(data, Not(HasSubstr(content2)));
EXPECT_THAT(data, HasSubstr(content3));
}));
protozero::ScatteredStreamWriter* writer =
tw_.NewTracePacket().TakeStreamWriter();
writer->WriteBytes(reinterpret_cast<const uint8_t*>(content1.data()),
content1.size());
tw_.FinishTracePacket();
{
auto msg = tw_.NewTracePacket();
msg->AppendRawProtoBytes(reinterpret_cast<const uint8_t*>(content2.data()),
content2.size());
}
writer = tw_.NewTracePacket().TakeStreamWriter();
writer->WriteBytes(reinterpret_cast<const uint8_t*>(content3.data()),
content3.size());
tw_.FinishTracePacket();
tw_.Flush();
}
TEST_F(InterceptorTraceWriterTest, FlushCallback) {
MockFunction<void()> flush_cb;
InSequence seq;
EXPECT_CALL(trace_packet_callback_, Call).Times(1);
EXPECT_CALL(flush_cb, Call).Times(1);
tw_.NewTracePacket();
tw_.Flush(flush_cb.AsStdFunction());
}
} // namespace internal
} // namespace perfetto