xref: /aosp_15_r20/external/perfetto/src/tracing/service/zlib_compressor_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/tracing/service/zlib_compressor.h"
18 
19 #include <random>
20 
21 #include <zlib.h>
22 
23 #include "protos/perfetto/trace/test_event.gen.h"
24 #include "protos/perfetto/trace/trace.gen.h"
25 #include "protos/perfetto/trace/trace_packet.gen.h"
26 #include "src/tracing/service/tracing_service_impl.h"
27 #include "test/gtest_and_gmock.h"
28 
29 namespace perfetto {
30 namespace {
31 
32 using ::testing::Each;
33 using ::testing::ElementsAre;
34 using ::testing::Field;
35 using ::testing::IsEmpty;
36 using ::testing::Le;
37 using ::testing::Not;
38 using ::testing::Property;
39 using ::testing::SizeIs;
40 
41 template <typename F>
CreateTracePacket(F fill_function)42 TracePacket CreateTracePacket(F fill_function) {
43   protos::gen::TracePacket msg;
44   fill_function(&msg);
45   std::vector<uint8_t> buf = msg.SerializeAsArray();
46   Slice slice = Slice::Allocate(buf.size());
47   memcpy(slice.own_data(), buf.data(), buf.size());
48   perfetto::TracePacket packet;
49   packet.AddSlice(std::move(slice));
50   return packet;
51 }
52 
53 // Return a copy of the `old` trace packets that owns its own slices data.
CopyTracePacket(const TracePacket & old)54 TracePacket CopyTracePacket(const TracePacket& old) {
55   TracePacket ret;
56   for (const Slice& slice : old.slices()) {
57     auto new_slice = Slice::Allocate(slice.size);
58     memcpy(new_slice.own_data(), slice.start, slice.size);
59     ret.AddSlice(std::move(new_slice));
60   }
61   return ret;
62 }
63 
CopyTracePackets(const std::vector<TracePacket> & old)64 std::vector<TracePacket> CopyTracePackets(const std::vector<TracePacket>& old) {
65   std::vector<TracePacket> ret;
66   ret.reserve(old.size());
67   for (const TracePacket& trace_packet : old) {
68     ret.push_back(CopyTracePacket(trace_packet));
69   }
70   return ret;
71 }
RandomString(size_t size)72 std::string RandomString(size_t size) {
73   std::default_random_engine rnd(0);
74   std::uniform_int_distribution<> dist(0, 255);
75   std::string s;
76   s.resize(size);
77   for (size_t i = 0; i < s.size(); i++)
78     s[i] = static_cast<char>(dist(rnd));
79   return s;
80 }
81 
Decompress(const std::string & data)82 std::string Decompress(const std::string& data) {
83   uint8_t out[1024];
84 
85   z_stream stream{};
86   stream.next_in = reinterpret_cast<uint8_t*>(const_cast<char*>(data.data()));
87   stream.avail_in = static_cast<unsigned int>(data.size());
88 
89   EXPECT_EQ(inflateInit(&stream), Z_OK);
90   std::string s;
91 
92   int ret;
93   do {
94     stream.next_out = out;
95     stream.avail_out = sizeof(out);
96     ret = inflate(&stream, Z_NO_FLUSH);
97     EXPECT_NE(ret, Z_STREAM_ERROR);
98     EXPECT_NE(ret, Z_NEED_DICT);
99     EXPECT_NE(ret, Z_DATA_ERROR);
100     EXPECT_NE(ret, Z_MEM_ERROR);
101     s.append(reinterpret_cast<char*>(out), sizeof(out) - stream.avail_out);
102   } while (ret != Z_STREAM_END);
103 
104   inflateEnd(&stream);
105   return s;
106 }
107 
108 static_assert(kZlibCompressSliceSize ==
109               TracingServiceImpl::kMaxTracePacketSliceSize);
110 
TEST(ZlibCompressFnTest,Empty)111 TEST(ZlibCompressFnTest, Empty) {
112   std::vector<TracePacket> packets;
113 
114   ZlibCompressFn(&packets);
115 
116   EXPECT_THAT(packets, IsEmpty());
117 }
118 
TEST(ZlibCompressFnTest,End2EndCompressAndDecompress)119 TEST(ZlibCompressFnTest, End2EndCompressAndDecompress) {
120   std::vector<TracePacket> packets;
121 
122   packets.push_back(CreateTracePacket([](protos::gen::TracePacket* msg) {
123     auto* for_testing = msg->mutable_for_testing();
124     for_testing->set_str("abc");
125   }));
126   packets.push_back(CreateTracePacket([](protos::gen::TracePacket* msg) {
127     auto* for_testing = msg->mutable_for_testing();
128     for_testing->set_str("def");
129   }));
130 
131   ZlibCompressFn(&packets);
132 
133   ASSERT_THAT(packets, SizeIs(1));
134   protos::gen::TracePacket compressed_packet_proto;
135   ASSERT_TRUE(compressed_packet_proto.ParseFromString(
136       packets[0].GetRawBytesForTesting()));
137   const std::string& data = compressed_packet_proto.compressed_packets();
138   EXPECT_THAT(data, Not(IsEmpty()));
139   protos::gen::Trace subtrace;
140   ASSERT_TRUE(subtrace.ParseFromString(Decompress(data)));
141   EXPECT_THAT(
142       subtrace.packet(),
143       ElementsAre(Property(&protos::gen::TracePacket::for_testing,
144                            Property(&protos::gen::TestEvent::str, "abc")),
145                   Property(&protos::gen::TracePacket::for_testing,
146                            Property(&protos::gen::TestEvent::str, "def"))));
147 }
148 
TEST(ZlibCompressFnTest,MaxSliceSize)149 TEST(ZlibCompressFnTest, MaxSliceSize) {
150   std::vector<TracePacket> packets;
151 
152   constexpr size_t kStopOutputSize =
153       TracingServiceImpl::kMaxTracePacketSliceSize + 2000;
154 
155   TracePacket compressed_packet;
156   while (compressed_packet.size() < kStopOutputSize) {
157     packets.push_back(CreateTracePacket([](protos::gen::TracePacket* msg) {
158       auto* for_testing = msg->mutable_for_testing();
159       for_testing->set_str(RandomString(65536));
160     }));
161     {
162       std::vector<TracePacket> packets_copy = CopyTracePackets(packets);
163       ZlibCompressFn(&packets_copy);
164       ASSERT_THAT(packets_copy, SizeIs(1));
165       compressed_packet = std::move(packets_copy[0]);
166     }
167   }
168 
169   EXPECT_GE(compressed_packet.slices().size(), 2u);
170   ASSERT_GT(compressed_packet.size(),
171             TracingServiceImpl::kMaxTracePacketSliceSize);
172   EXPECT_THAT(compressed_packet.slices(),
173               Each(Field(&Slice::size,
174                          Le(TracingServiceImpl::kMaxTracePacketSliceSize))));
175 }
176 
177 }  // namespace
178 }  // namespace perfetto
179