/* * 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; InterceptorTraceWriterTest() : tls_ptr_(new ThreadLocalState()), tw_(std::unique_ptr(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 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 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(content1.data()), content1.size()); tw_.FinishTracePacket(); { auto msg = tw_.NewTracePacket(); msg->AppendRawProtoBytes(reinterpret_cast(content2.data()), content2.size()); } writer = tw_.NewTracePacket().TakeStreamWriter(); writer->WriteBytes(reinterpret_cast(content3.data()), content3.size()); tw_.FinishTracePacket(); tw_.Flush(); } TEST_F(InterceptorTraceWriterTest, FlushCallback) { MockFunction 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