xref: /aosp_15_r20/external/perfetto/src/trace_redaction/process_thread_timeline_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2024 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 <array>
18 #include <cstdint>
19 
20 #include "src/trace_redaction/process_thread_timeline.h"
21 #include "test/gtest_and_gmock.h"
22 
23 namespace perfetto::trace_redaction {
24 
25 namespace {
26 
27 constexpr uint64_t kTimeA = 0;
28 constexpr uint64_t kTimeB = 10;
29 constexpr uint64_t kTimeC = 20;
30 constexpr uint64_t kTimeD = 30;
31 constexpr uint64_t kTimeE = 40;
32 constexpr uint64_t kTimeF = 50;
33 constexpr uint64_t kTimeG = 60;
34 constexpr uint64_t kTimeH = 70;
35 
36 constexpr int32_t kPidA = 1;
37 constexpr int32_t kPidB = 2;
38 constexpr int32_t kPidC = 3;
39 constexpr int32_t kPidD = 4;
40 
41 constexpr uint64_t kUidA = 97;
42 constexpr uint64_t kUidC = 99;
43 
44 }  // namespace
45 
46 // B        C        D   E   F        G        H
47 // *        *        *   *   *        *        *
48 // |----- PID B -----|   .   |----- PID B -----|
49 //          |--------- PID C ---------|
50 //          | <- PID D (no duration)
51 class ProcessThreadTimelineTest : public testing::Test {
52  protected:
SetUp()53   void SetUp() {
54     for (auto e : pid_b_events_) {
55       timeline_.Append(e);
56     }
57 
58     for (auto e : pid_c_events_) {
59       timeline_.Append(e);
60     }
61 
62     for (auto e : pid_d_events_) {
63       timeline_.Append(e);
64     }
65 
66     timeline_.Sort();
67   }
68 
69   ProcessThreadTimeline::Event invalid_ = {};
70 
71   std::array<ProcessThreadTimeline::Event, 4> pid_b_events_ = {
72       ProcessThreadTimeline::Event::Open(kTimeB, kPidB, kPidA, kUidA),
73       ProcessThreadTimeline::Event::Close(kTimeD, kPidB),
74       ProcessThreadTimeline::Event::Open(kTimeF, kPidB, kPidA, kUidA),
75       ProcessThreadTimeline::Event::Close(kTimeH, kPidB),
76   };
77 
78   std::array<ProcessThreadTimeline::Event, 2> pid_c_events_ = {
79       ProcessThreadTimeline::Event::Open(kTimeC, kPidC, kPidA, kUidA),
80       ProcessThreadTimeline::Event::Close(kTimeG, kPidC),
81   };
82 
83   // A process with no duration.
84   std::array<ProcessThreadTimeline::Event, 2> pid_d_events_{
85       ProcessThreadTimeline::Event::Open(kTimeC, kPidD, kPidA, kUidA),
86       ProcessThreadTimeline::Event::Close(kTimeC, kPidD),
87   };
88 
89   ProcessThreadTimeline timeline_;
90 };
91 
TEST_F(ProcessThreadTimelineTest,BeforeSpan)92 TEST_F(ProcessThreadTimelineTest, BeforeSpan) {
93   auto prev_open = timeline_.QueryLeftMax(
94       kTimeA, kPidB, ProcessThreadTimeline::Event::Type::kOpen);
95   ASSERT_FALSE(prev_open);
96 
97   auto prev_close = timeline_.QueryLeftMax(
98       kTimeA, kPidB, ProcessThreadTimeline::Event::Type::kClose);
99   ASSERT_FALSE(prev_close);
100 }
101 
TEST_F(ProcessThreadTimelineTest,StartOfSpan)102 TEST_F(ProcessThreadTimelineTest, StartOfSpan) {
103   auto prev_open = timeline_.QueryLeftMax(
104       kTimeB, kPidB, ProcessThreadTimeline::Event::Type::kOpen);
105   ASSERT_TRUE(prev_open);
106   ASSERT_EQ(*prev_open, pid_b_events_[0]);
107 
108   auto prev_close = timeline_.QueryLeftMax(
109       kTimeB, kPidB, ProcessThreadTimeline::Event::Type::kClose);
110   ASSERT_FALSE(prev_close);
111 }
112 
TEST_F(ProcessThreadTimelineTest,DuringSpan)113 TEST_F(ProcessThreadTimelineTest, DuringSpan) {
114   auto prev_open = timeline_.QueryLeftMax(
115       kTimeC, kPidB, ProcessThreadTimeline::Event::Type::kOpen);
116   ASSERT_TRUE(prev_open);
117   ASSERT_EQ(*prev_open, pid_b_events_[0]);
118 
119   auto prev_close = timeline_.QueryLeftMax(
120       kTimeC, kPidB, ProcessThreadTimeline::Event::Type::kClose);
121   ASSERT_FALSE(prev_close);
122 }
123 
TEST_F(ProcessThreadTimelineTest,EndOfSpan)124 TEST_F(ProcessThreadTimelineTest, EndOfSpan) {
125   auto prev_open = timeline_.QueryLeftMax(
126       kTimeD, kPidB, ProcessThreadTimeline::Event::Type::kOpen);
127   ASSERT_TRUE(prev_open);
128   ASSERT_EQ(*prev_open, pid_b_events_[0]);
129 
130   auto prev_close = timeline_.QueryLeftMax(
131       kTimeD, kPidB, ProcessThreadTimeline::Event::Type::kClose);
132   ASSERT_TRUE(prev_close);
133   ASSERT_EQ(*prev_close, pid_b_events_[1]);
134 }
135 
136 // Even through its after a span, the previous open and close events should be
137 // openned.
TEST_F(ProcessThreadTimelineTest,AfterSpan)138 TEST_F(ProcessThreadTimelineTest, AfterSpan) {
139   auto prev_open = timeline_.QueryLeftMax(
140       kTimeE, kPidB, ProcessThreadTimeline::Event::Type::kOpen);
141   ASSERT_TRUE(prev_open);
142   ASSERT_EQ(*prev_open, pid_b_events_[0]);
143 
144   auto prev_close = timeline_.QueryLeftMax(
145       kTimeE, kPidB, ProcessThreadTimeline::Event::Type::kClose);
146   ASSERT_TRUE(prev_close);
147   ASSERT_EQ(*prev_close, pid_b_events_[1]);
148 }
149 
150 // When a pid is reused, the new open event (for the reused pid) should be
151 // returned, but the close from the previous span should be returned.
TEST_F(ProcessThreadTimelineTest,StartOfSecondSpan)152 TEST_F(ProcessThreadTimelineTest, StartOfSecondSpan) {
153   auto prev_open = timeline_.QueryLeftMax(
154       kTimeF, kPidB, ProcessThreadTimeline::Event::Type::kOpen);
155   ASSERT_TRUE(prev_open);
156   ASSERT_EQ(*prev_open, pid_b_events_[2]);
157 
158   auto prev_close = timeline_.QueryLeftMax(
159       kTimeF, kPidB, ProcessThreadTimeline::Event::Type::kClose);
160   ASSERT_TRUE(prev_close);
161   ASSERT_EQ(*prev_close, pid_b_events_[1]);
162 }
163 
164 // Now that there is a second close event, both open and close events should
165 // come from the same span.
TEST_F(ProcessThreadTimelineTest,CloseOfSecondSpan)166 TEST_F(ProcessThreadTimelineTest, CloseOfSecondSpan) {
167   auto prev_open = timeline_.QueryLeftMax(
168       kTimeH, kPidB, ProcessThreadTimeline::Event::Type::kOpen);
169   ASSERT_TRUE(prev_open);
170   ASSERT_EQ(*prev_open, pid_b_events_[2]);
171 
172   auto prev_close = timeline_.QueryLeftMax(
173       kTimeH, kPidB, ProcessThreadTimeline::Event::Type::kClose);
174   ASSERT_TRUE(prev_close);
175   ASSERT_EQ(*prev_close, pid_b_events_[3]);
176 }
177 
TEST_F(ProcessThreadTimelineTest,BeforeSpanWithZeroDuration)178 TEST_F(ProcessThreadTimelineTest, BeforeSpanWithZeroDuration) {
179   auto prev_open = timeline_.QueryLeftMax(
180       kTimeA, kPidD, ProcessThreadTimeline::Event::Type::kOpen);
181   ASSERT_FALSE(prev_open);
182 
183   auto prev_close = timeline_.QueryLeftMax(
184       kTimeA, kPidD, ProcessThreadTimeline::Event::Type::kClose);
185   ASSERT_FALSE(prev_close);
186 }
187 
TEST_F(ProcessThreadTimelineTest,SpanWithZeroDuration)188 TEST_F(ProcessThreadTimelineTest, SpanWithZeroDuration) {
189   auto prev_open = timeline_.QueryLeftMax(
190       kTimeC, kPidD, ProcessThreadTimeline::Event::Type::kOpen);
191   ASSERT_TRUE(prev_open);
192   ASSERT_EQ(*prev_open, pid_d_events_[0]);
193 
194   auto prev_close = timeline_.QueryLeftMax(
195       kTimeC, kPidD, ProcessThreadTimeline::Event::Type::kClose);
196   ASSERT_TRUE(prev_close);
197   ASSERT_EQ(*prev_close, pid_d_events_[1]);
198 }
199 
TEST_F(ProcessThreadTimelineTest,AfterSpanWithZeroDuration)200 TEST_F(ProcessThreadTimelineTest, AfterSpanWithZeroDuration) {
201   auto prev_open = timeline_.QueryLeftMax(
202       kTimeE, kPidD, ProcessThreadTimeline::Event::Type::kOpen);
203   ASSERT_TRUE(prev_open);
204 
205   auto prev_close = timeline_.QueryLeftMax(
206       kTimeE, kPidD, ProcessThreadTimeline::Event::Type::kClose);
207   ASSERT_TRUE(prev_close);
208 }
209 
210 // |----- UID A -----| |----- UID C -----|
211 //  |---- PID A ----|   |---- PID C ----|
212 //    |-- PID B --|
213 //
214 // NOTE: The notation above does not represent time, it represent relationship.
215 // For example, PID B is a child of PID A.
216 class ProcessThreadTimelineIsConnectedTest : public testing::Test {
217  protected:
SetUp()218   void SetUp() {
219     timeline_.Append(ProcessThreadTimeline::Event::Open(
220         kTimeB, kPidA, ProcessThreadTimeline::Event::kUnknownPid, kUidA));
221     timeline_.Append(ProcessThreadTimeline::Event::Open(kTimeB, kPidB, kPidA));
222     timeline_.Append(ProcessThreadTimeline::Event::Open(
223         kTimeB, kPidC, ProcessThreadTimeline::Event::kUnknownPid, kUidC));
224     timeline_.Sort();
225   }
226 
227   ProcessThreadTimeline timeline_;
228 };
229 
230 // PID A is directly connected to UID A.
TEST_F(ProcessThreadTimelineIsConnectedTest,DirectPidAndUid)231 TEST_F(ProcessThreadTimelineIsConnectedTest, DirectPidAndUid) {
232   ASSERT_TRUE(timeline_.PidConnectsToUid(kTimeB, kPidA, kUidA));
233 }
234 
235 // PID B is indirectly connected to UID A through PID A.
TEST_F(ProcessThreadTimelineIsConnectedTest,IndirectPidAndUid)236 TEST_F(ProcessThreadTimelineIsConnectedTest, IndirectPidAndUid) {
237   ASSERT_TRUE(timeline_.PidConnectsToUid(kTimeB, kPidB, kUidA));
238 }
239 
240 // UID A and UID C are valid packages. However, PID B is connected to UID A, not
241 // UID C.
TEST_F(ProcessThreadTimelineIsConnectedTest,NotConnectedToOtherUid)242 TEST_F(ProcessThreadTimelineIsConnectedTest, NotConnectedToOtherUid) {
243   ASSERT_FALSE(timeline_.PidConnectsToUid(kTimeB, kPidB, kUidC));
244 }
245 
246 // PID D is not in the timeline, so it shouldn't be connected to anything.
TEST_F(ProcessThreadTimelineIsConnectedTest,MissingPid)247 TEST_F(ProcessThreadTimelineIsConnectedTest, MissingPid) {
248   ASSERT_FALSE(timeline_.PidConnectsToUid(kTimeB, kPidD, kUidA));
249 }
250 
251 // Even through there is a connection between PID A and UID A, the query is too
252 // soon (events are at TIME B, but the query is at TIME A).
TEST_F(ProcessThreadTimelineIsConnectedTest,PrematureDirectPidAndUid)253 TEST_F(ProcessThreadTimelineIsConnectedTest, PrematureDirectPidAndUid) {
254   ASSERT_FALSE(timeline_.PidConnectsToUid(kTimeA, kPidA, kUidA));
255 }
256 
257 }  // namespace perfetto::trace_redaction
258