xref: /aosp_15_r20/development/tools/winscope/src/trace/traces_test.ts (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
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
17import {assertDefined} from 'common/assert_utils';
18import {FunctionUtils} from 'common/function_utils';
19import {TimestampConverterUtils} from 'test/unit/timestamp_converter_utils';
20import {TracesBuilder} from 'test/unit/traces_builder';
21import {TracesUtils} from 'test/unit/traces_utils';
22import {TraceBuilder} from 'test/unit/trace_builder';
23import {TraceUtils} from 'test/unit/trace_utils';
24import {UnitTestUtils} from 'test/unit/utils';
25import {FrameMapBuilder} from './frame_map_builder';
26import {AbsoluteFrameIndex} from './index_types';
27import {Traces} from './traces';
28import {TraceType} from './trace_type';
29
30describe('Traces', () => {
31  let traces: Traces;
32
33  const time1 = TimestampConverterUtils.makeRealTimestamp(1n);
34  const time2 = TimestampConverterUtils.makeRealTimestamp(2n);
35  const time3 = TimestampConverterUtils.makeRealTimestamp(3n);
36  const time4 = TimestampConverterUtils.makeRealTimestamp(4n);
37  const time5 = TimestampConverterUtils.makeRealTimestamp(5n);
38  const time6 = TimestampConverterUtils.makeRealTimestamp(6n);
39  const time7 = TimestampConverterUtils.makeRealTimestamp(7n);
40  const time8 = TimestampConverterUtils.makeRealTimestamp(8n);
41  const time9 = TimestampConverterUtils.makeRealTimestamp(9n);
42  const time10 = TimestampConverterUtils.makeRealTimestamp(10n);
43
44  let extractedEntriesEmpty: Map<TraceType, Array<{}>>;
45  let extractedEntriesFull: Map<TraceType, Array<{}>>;
46  let extractedFramesEmpty: Map<AbsoluteFrameIndex, Map<TraceType, Array<{}>>>;
47  let extractedFramesFull: Map<AbsoluteFrameIndex, Map<TraceType, Array<{}>>>;
48
49  beforeAll(() => {
50    // Time:               1  2  3  4  5  6  7  8  9 10
51    //
52    // TEST_TRACE_STRING:  0     1--2     3        4
53    //                      \        \     \        \
54    //                       \        \     \        \
55    // TEST_TRACE_NUMBER:     0        1     2--3     4
56    //                         \        \        \     \
57    //                          \        \        \     \
58    // Frame on screen:          0        1        2     3---4
59    traces = new Traces();
60    traces.addTrace(
61      new TraceBuilder<string>()
62        .setType(TraceType.TEST_TRACE_STRING)
63        .setEntries(['0', '1', '2', '3', '4'])
64        .setTimestamps([time1, time3, time4, time6, time9])
65        .setFrame(0, 0)
66        .setFrame(1, 1)
67        .setFrame(2, 1)
68        .setFrame(3, 2)
69        .setFrame(4, 3)
70        .setFrame(4, 4)
71        .build(),
72    );
73    traces.addTrace(
74      new TraceBuilder<number>()
75        .setType(TraceType.TEST_TRACE_NUMBER)
76        .setEntries([0, 1, 2, 3, 4])
77        .setTimestamps([time2, time5, time7, time8, time10])
78        .setFrame(0, 0)
79        .setFrame(1, 1)
80        .setFrame(2, 2)
81        .setFrame(3, 2)
82        .setFrame(4, 3)
83        .setFrame(4, 4)
84        .build(),
85    );
86
87    extractedEntriesEmpty = new Map<TraceType, Array<{}>>([
88      [TraceType.TEST_TRACE_STRING, []],
89      [TraceType.TEST_TRACE_NUMBER, []],
90    ]);
91
92    extractedEntriesFull = new Map<TraceType, Array<{}>>([
93      [TraceType.TEST_TRACE_STRING, ['0', '1', '2', '3', '4']],
94      [TraceType.TEST_TRACE_NUMBER, [0, 1, 2, 3, 4]],
95    ]);
96
97    extractedFramesEmpty = new Map<
98      AbsoluteFrameIndex,
99      Map<TraceType, Array<{}>>
100    >();
101
102    extractedFramesFull = new Map<
103      AbsoluteFrameIndex,
104      Map<TraceType, Array<{}>>
105    >();
106    extractedFramesFull.set(
107      0,
108      new Map<TraceType, Array<{}>>([
109        [TraceType.TEST_TRACE_STRING, ['0']],
110        [TraceType.TEST_TRACE_NUMBER, [0]],
111      ]),
112    );
113    extractedFramesFull.set(
114      1,
115      new Map<TraceType, Array<{}>>([
116        [TraceType.TEST_TRACE_STRING, ['1', '2']],
117        [TraceType.TEST_TRACE_NUMBER, [1]],
118      ]),
119    );
120    extractedFramesFull.set(
121      2,
122      new Map<TraceType, Array<{}>>([
123        [TraceType.TEST_TRACE_STRING, ['3']],
124        [TraceType.TEST_TRACE_NUMBER, [2, 3]],
125      ]),
126    );
127    extractedFramesFull.set(
128      3,
129      new Map<TraceType, Array<{}>>([
130        [TraceType.TEST_TRACE_STRING, ['4']],
131        [TraceType.TEST_TRACE_NUMBER, [4]],
132      ]),
133    );
134    extractedFramesFull.set(
135      4,
136      new Map<TraceType, Array<{}>>([
137        [TraceType.TEST_TRACE_STRING, ['4']],
138        [TraceType.TEST_TRACE_NUMBER, [4]],
139      ]),
140    );
141  });
142
143  it('getTrace()', async () => {
144    expect(
145      await TraceUtils.extractEntries(
146        assertDefined(traces.getTrace(TraceType.TEST_TRACE_STRING)),
147      ),
148    ).toEqual(
149      extractedEntriesFull.get(TraceType.TEST_TRACE_STRING) as string[],
150    );
151    expect(
152      await TraceUtils.extractEntries(
153        assertDefined(traces.getTrace(TraceType.TEST_TRACE_NUMBER)),
154      ),
155    ).toEqual(
156      extractedEntriesFull.get(TraceType.TEST_TRACE_NUMBER) as number[],
157    );
158    expect(traces.getTrace(TraceType.SURFACE_FLINGER)).toBeUndefined();
159  });
160
161  it('getTraces()', async () => {
162    expect(traces.getTraces(TraceType.TEST_TRACE_NUMBER)).toEqual([
163      assertDefined(traces.getTrace(TraceType.TEST_TRACE_NUMBER)),
164    ]);
165  });
166
167  it('deleteTrace()', () => {
168    const trace0 = UnitTestUtils.makeEmptyTrace(TraceType.TEST_TRACE_STRING);
169    const trace1 = UnitTestUtils.makeEmptyTrace(TraceType.TEST_TRACE_NUMBER);
170
171    const traces = new Traces();
172    traces.addTrace(trace0);
173    traces.addTrace(trace1);
174
175    expect(TracesUtils.extractTraces(traces)).toEqual([trace0, trace1]);
176
177    traces.deleteTrace(trace0);
178    expect(TracesUtils.extractTraces(traces)).toEqual([trace1]);
179
180    traces.deleteTrace(trace1);
181    expect(TracesUtils.extractTraces(traces)).toEqual([]);
182
183    traces.deleteTrace(trace1);
184    expect(TracesUtils.extractTraces(traces)).toEqual([]);
185  });
186
187  it('hasTrace()', () => {
188    const trace0 = UnitTestUtils.makeEmptyTrace(TraceType.TEST_TRACE_STRING);
189    const trace1 = UnitTestUtils.makeEmptyTrace(TraceType.TEST_TRACE_NUMBER);
190
191    const traces = new Traces();
192    traces.addTrace(trace0);
193
194    expect(traces.hasTrace(trace0)).toBeTrue();
195    expect(traces.hasTrace(trace1)).toBeFalse();
196  });
197
198  it('sliceTime()', async () => {
199    // empty
200    {
201      const slice = traces.sliceTime(time3, time3);
202      expect(await TracesUtils.extractEntries(slice)).toEqual(
203        extractedEntriesEmpty,
204      );
205    }
206    // full
207    {
208      const slice = traces.sliceTime();
209      expect(await TracesUtils.extractEntries(slice)).toEqual(
210        extractedEntriesFull,
211      );
212    }
213    // middle
214    {
215      const slice = traces.sliceTime(time4, time8);
216      expect(await TracesUtils.extractEntries(slice)).toEqual(
217        new Map<TraceType, Array<{}>>([
218          [TraceType.TEST_TRACE_STRING, ['2', '3']],
219          [TraceType.TEST_TRACE_NUMBER, [1, 2]],
220        ]),
221      );
222    }
223    // slice away front
224    {
225      const slice = traces.sliceTime(time8);
226      expect(await TracesUtils.extractEntries(slice)).toEqual(
227        new Map<TraceType, Array<{}>>([
228          [TraceType.TEST_TRACE_STRING, ['4']],
229          [TraceType.TEST_TRACE_NUMBER, [3, 4]],
230        ]),
231      );
232    }
233    // slice away back
234    {
235      const slice = traces.sliceTime(undefined, time8);
236      expect(await TracesUtils.extractEntries(slice)).toEqual(
237        new Map<TraceType, Array<{}>>([
238          [TraceType.TEST_TRACE_STRING, ['0', '1', '2', '3']],
239          [TraceType.TEST_TRACE_NUMBER, [0, 1, 2]],
240        ]),
241      );
242    }
243  });
244
245  it('sliceFrames()', async () => {
246    // empty
247    {
248      const slice = traces.sliceFrames(1, 1);
249      expect(await TracesUtils.extractFrames(slice)).toEqual(
250        extractedFramesEmpty,
251      );
252    }
253    // full
254    {
255      const slice = traces.sliceFrames();
256      expect(await TracesUtils.extractFrames(slice)).toEqual(
257        extractedFramesFull,
258      );
259    }
260    // middle
261    {
262      const slice = traces.sliceFrames(1, 4);
263      const expectedFrames = structuredClone(extractedFramesFull);
264      expectedFrames.delete(0);
265      expectedFrames.delete(4);
266      expect(await TracesUtils.extractFrames(slice)).toEqual(expectedFrames);
267    }
268    // slice away front
269    {
270      const slice = traces.sliceFrames(2);
271      const expectedFrames = structuredClone(extractedFramesFull);
272      expectedFrames.delete(0);
273      expectedFrames.delete(1);
274      expect(await TracesUtils.extractFrames(slice)).toEqual(expectedFrames);
275    }
276    // slice away back
277    {
278      const slice = traces.sliceFrames(undefined, 2);
279      const expectedFrames = structuredClone(extractedFramesFull);
280      expectedFrames.delete(2);
281      expectedFrames.delete(3);
282      expectedFrames.delete(4);
283      expect(await TracesUtils.extractFrames(slice)).toEqual(expectedFrames);
284    }
285  });
286
287  it('mapTrace()', async () => {
288    const promises = traces.mapTrace(async (trace) => {
289      const expectedEntries = extractedEntriesFull.get(trace.type) as Array<{}>;
290      const actualEntries = await TraceUtils.extractEntries(trace);
291      expect(actualEntries).toEqual(expectedEntries);
292    });
293    await Promise.all(promises);
294  });
295
296  it('mapFrame()', async () => {
297    expect(await TracesUtils.extractFrames(traces)).toEqual(
298      extractedFramesFull,
299    );
300  });
301
302  it('supports empty traces', async () => {
303    const traces = new TracesBuilder()
304      .setEntries(TraceType.TEST_TRACE_STRING, [])
305      .setFrameMap(
306        TraceType.TEST_TRACE_STRING,
307        new FrameMapBuilder(0, 0).build(),
308      )
309
310      .setEntries(TraceType.TEST_TRACE_NUMBER, [])
311      .setFrameMap(
312        TraceType.TEST_TRACE_NUMBER,
313        new FrameMapBuilder(0, 0).build(),
314      )
315      .build();
316
317    expect(await TracesUtils.extractEntries(traces)).toEqual(
318      extractedEntriesEmpty,
319    );
320    expect(await TracesUtils.extractFrames(traces)).toEqual(
321      extractedFramesEmpty,
322    );
323
324    expect(
325      await TracesUtils.extractEntries(traces.sliceTime(time1, time10)),
326    ).toEqual(extractedEntriesEmpty);
327    expect(
328      await TracesUtils.extractFrames(traces.sliceTime(time1, time10)),
329    ).toEqual(extractedFramesEmpty);
330
331    expect(await TracesUtils.extractEntries(traces.sliceFrames(0, 10))).toEqual(
332      extractedEntriesEmpty,
333    );
334    expect(await TracesUtils.extractFrames(traces.sliceFrames(0, 10))).toEqual(
335      extractedFramesEmpty,
336    );
337  });
338
339  it('supports unavailable frame mapping', async () => {
340    const traces = new TracesBuilder()
341      .setEntries(TraceType.TEST_TRACE_STRING, ['entry-0'])
342      .setTimestamps(TraceType.TEST_TRACE_STRING, [time1])
343      .setFrameMap(TraceType.TEST_TRACE_STRING, undefined)
344
345      .setEntries(TraceType.TEST_TRACE_NUMBER, [0])
346      .setTimestamps(TraceType.TEST_TRACE_NUMBER, [time1])
347      .setFrameMap(TraceType.TEST_TRACE_NUMBER, undefined)
348      .build();
349
350    const expectedEntries = new Map<TraceType, Array<{}>>([
351      [TraceType.TEST_TRACE_STRING, ['entry-0']],
352      [TraceType.TEST_TRACE_NUMBER, [0]],
353    ]);
354
355    expect(await TracesUtils.extractEntries(traces)).toEqual(expectedEntries);
356    expect(await TracesUtils.extractEntries(traces.sliceTime())).toEqual(
357      expectedEntries,
358    );
359
360    expect(() => {
361      traces.sliceFrames();
362    }).toThrow();
363    expect(() => {
364      traces.forEachFrame(FunctionUtils.DO_NOTHING);
365    }).toThrow();
366    expect(() => {
367      traces.mapFrame(FunctionUtils.DO_NOTHING);
368    }).toThrow();
369  });
370
371  it('supports multiple traces with same type', () => {
372    const traceShort = new TraceBuilder<number>()
373      .setType(TraceType.TEST_TRACE_NUMBER)
374      .setEntries([0])
375      .build();
376    const traceLong = new TraceBuilder<number>()
377      .setType(TraceType.TEST_TRACE_NUMBER)
378      .setEntries([1, 2])
379      .build();
380
381    const traces = new Traces();
382    traces.addTrace(traceShort);
383    traces.addTrace(traceLong);
384
385    expect(traces.getTraces(TraceType.TEST_TRACE_NUMBER)).toEqual([
386      traceShort,
387      traceLong,
388    ]);
389    expect(traces.getTrace(TraceType.TEST_TRACE_NUMBER)).toEqual(traceLong);
390  });
391});
392