xref: /aosp_15_r20/development/tools/winscope/src/test/unit/utils.ts (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1*90c8c64dSAndroid Build Coastguard Worker/*
2*90c8c64dSAndroid Build Coastguard Worker * Copyright (C) 2022 The Android Open Source Project
3*90c8c64dSAndroid Build Coastguard Worker *
4*90c8c64dSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*90c8c64dSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*90c8c64dSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*90c8c64dSAndroid Build Coastguard Worker *
8*90c8c64dSAndroid Build Coastguard Worker *      http://www.apache.org/licenses/LICENSE-2.0
9*90c8c64dSAndroid Build Coastguard Worker *
10*90c8c64dSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*90c8c64dSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*90c8c64dSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*90c8c64dSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*90c8c64dSAndroid Build Coastguard Worker * limitations under the License.
15*90c8c64dSAndroid Build Coastguard Worker */
16*90c8c64dSAndroid Build Coastguard Worker
17*90c8c64dSAndroid Build Coastguard Workerimport {ComponentFixture} from '@angular/core/testing';
18*90c8c64dSAndroid Build Coastguard Workerimport {assertDefined} from 'common/assert_utils';
19*90c8c64dSAndroid Build Coastguard Workerimport {Timestamp} from 'common/time';
20*90c8c64dSAndroid Build Coastguard Workerimport {TimestampConverter} from 'common/timestamp_converter';
21*90c8c64dSAndroid Build Coastguard Workerimport {UrlUtils} from 'common/url_utils';
22*90c8c64dSAndroid Build Coastguard Workerimport {ParserFactory as LegacyParserFactory} from 'parsers/legacy/parser_factory';
23*90c8c64dSAndroid Build Coastguard Workerimport {ParserFactory as PerfettoParserFactory} from 'parsers/perfetto/parser_factory';
24*90c8c64dSAndroid Build Coastguard Workerimport {TracesParserFactory} from 'parsers/traces/traces_parser_factory';
25*90c8c64dSAndroid Build Coastguard Workerimport {Parser} from 'trace/parser';
26*90c8c64dSAndroid Build Coastguard Workerimport {Trace} from 'trace/trace';
27*90c8c64dSAndroid Build Coastguard Workerimport {Traces} from 'trace/traces';
28*90c8c64dSAndroid Build Coastguard Workerimport {TraceFile} from 'trace/trace_file';
29*90c8c64dSAndroid Build Coastguard Workerimport {TraceMetadata} from 'trace/trace_metadata';
30*90c8c64dSAndroid Build Coastguard Workerimport {TraceEntryTypeMap, TraceType} from 'trace/trace_type';
31*90c8c64dSAndroid Build Coastguard Workerimport {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node';
32*90c8c64dSAndroid Build Coastguard Workerimport {QueryResult, Row, RowIterator} from 'trace_processor/query_result';
33*90c8c64dSAndroid Build Coastguard Workerimport {TraceProcessorFactory} from 'trace_processor/trace_processor_factory';
34*90c8c64dSAndroid Build Coastguard Workerimport {TimestampConverterUtils} from './timestamp_converter_utils';
35*90c8c64dSAndroid Build Coastguard Workerimport {TraceBuilder} from './trace_builder';
36*90c8c64dSAndroid Build Coastguard Worker
37*90c8c64dSAndroid Build Coastguard Workerclass UnitTestUtils {
38*90c8c64dSAndroid Build Coastguard Worker  static async getFixtureFile(
39*90c8c64dSAndroid Build Coastguard Worker    srcFilename: string,
40*90c8c64dSAndroid Build Coastguard Worker    dstFilename: string = srcFilename,
41*90c8c64dSAndroid Build Coastguard Worker  ): Promise<File> {
42*90c8c64dSAndroid Build Coastguard Worker    const url = UrlUtils.getRootUrl() + 'base/src/test/fixtures/' + srcFilename;
43*90c8c64dSAndroid Build Coastguard Worker    const response = await fetch(url);
44*90c8c64dSAndroid Build Coastguard Worker    expect(response.ok).toBeTrue();
45*90c8c64dSAndroid Build Coastguard Worker    const blob = await response.blob();
46*90c8c64dSAndroid Build Coastguard Worker    const file = new File([blob], dstFilename);
47*90c8c64dSAndroid Build Coastguard Worker    return file;
48*90c8c64dSAndroid Build Coastguard Worker  }
49*90c8c64dSAndroid Build Coastguard Worker
50*90c8c64dSAndroid Build Coastguard Worker  static async getTrace<T extends TraceType>(
51*90c8c64dSAndroid Build Coastguard Worker    type: T,
52*90c8c64dSAndroid Build Coastguard Worker    filename: string,
53*90c8c64dSAndroid Build Coastguard Worker  ): Promise<Trace<T>> {
54*90c8c64dSAndroid Build Coastguard Worker    const converter = UnitTestUtils.getTimestampConverter(false);
55*90c8c64dSAndroid Build Coastguard Worker    const legacyParsers = await UnitTestUtils.getParsers(filename, converter);
56*90c8c64dSAndroid Build Coastguard Worker    expect(legacyParsers.length).toBeLessThanOrEqual(1);
57*90c8c64dSAndroid Build Coastguard Worker    if (legacyParsers.length === 1) {
58*90c8c64dSAndroid Build Coastguard Worker      expect(legacyParsers[0].getTraceType()).toEqual(type);
59*90c8c64dSAndroid Build Coastguard Worker      return new TraceBuilder<T>()
60*90c8c64dSAndroid Build Coastguard Worker        .setType(type)
61*90c8c64dSAndroid Build Coastguard Worker        .setParser(legacyParsers[0] as unknown as Parser<T>)
62*90c8c64dSAndroid Build Coastguard Worker        .build();
63*90c8c64dSAndroid Build Coastguard Worker    }
64*90c8c64dSAndroid Build Coastguard Worker
65*90c8c64dSAndroid Build Coastguard Worker    const perfettoParsers = await UnitTestUtils.getPerfettoParsers(filename);
66*90c8c64dSAndroid Build Coastguard Worker    expect(perfettoParsers.length).toEqual(1);
67*90c8c64dSAndroid Build Coastguard Worker    expect(perfettoParsers[0].getTraceType()).toEqual(type);
68*90c8c64dSAndroid Build Coastguard Worker    return new TraceBuilder<T>()
69*90c8c64dSAndroid Build Coastguard Worker      .setType(type)
70*90c8c64dSAndroid Build Coastguard Worker      .setParser(perfettoParsers[0] as unknown as Parser<T>)
71*90c8c64dSAndroid Build Coastguard Worker      .build();
72*90c8c64dSAndroid Build Coastguard Worker  }
73*90c8c64dSAndroid Build Coastguard Worker
74*90c8c64dSAndroid Build Coastguard Worker  static async getParser(
75*90c8c64dSAndroid Build Coastguard Worker    filename: string,
76*90c8c64dSAndroid Build Coastguard Worker    converter = UnitTestUtils.getTimestampConverter(),
77*90c8c64dSAndroid Build Coastguard Worker    initializeRealToElapsedTimeOffsetNs = true,
78*90c8c64dSAndroid Build Coastguard Worker    metadata: TraceMetadata = {},
79*90c8c64dSAndroid Build Coastguard Worker  ): Promise<Parser<object>> {
80*90c8c64dSAndroid Build Coastguard Worker    const parsers = await UnitTestUtils.getParsers(
81*90c8c64dSAndroid Build Coastguard Worker      filename,
82*90c8c64dSAndroid Build Coastguard Worker      converter,
83*90c8c64dSAndroid Build Coastguard Worker      initializeRealToElapsedTimeOffsetNs,
84*90c8c64dSAndroid Build Coastguard Worker      metadata,
85*90c8c64dSAndroid Build Coastguard Worker    );
86*90c8c64dSAndroid Build Coastguard Worker
87*90c8c64dSAndroid Build Coastguard Worker    expect(parsers.length)
88*90c8c64dSAndroid Build Coastguard Worker      .withContext(`Should have been able to create a parser for ${filename}`)
89*90c8c64dSAndroid Build Coastguard Worker      .toBeGreaterThanOrEqual(1);
90*90c8c64dSAndroid Build Coastguard Worker
91*90c8c64dSAndroid Build Coastguard Worker    return parsers[0];
92*90c8c64dSAndroid Build Coastguard Worker  }
93*90c8c64dSAndroid Build Coastguard Worker
94*90c8c64dSAndroid Build Coastguard Worker  static async getParsers(
95*90c8c64dSAndroid Build Coastguard Worker    filename: string,
96*90c8c64dSAndroid Build Coastguard Worker    converter = UnitTestUtils.getTimestampConverter(),
97*90c8c64dSAndroid Build Coastguard Worker    initializeRealToElapsedTimeOffsetNs = true,
98*90c8c64dSAndroid Build Coastguard Worker    metadata: TraceMetadata = {},
99*90c8c64dSAndroid Build Coastguard Worker  ): Promise<Array<Parser<object>>> {
100*90c8c64dSAndroid Build Coastguard Worker    const file = new TraceFile(
101*90c8c64dSAndroid Build Coastguard Worker      await UnitTestUtils.getFixtureFile(filename),
102*90c8c64dSAndroid Build Coastguard Worker      undefined,
103*90c8c64dSAndroid Build Coastguard Worker    );
104*90c8c64dSAndroid Build Coastguard Worker    const fileAndParsers = await new LegacyParserFactory().createParsers(
105*90c8c64dSAndroid Build Coastguard Worker      [file],
106*90c8c64dSAndroid Build Coastguard Worker      converter,
107*90c8c64dSAndroid Build Coastguard Worker      metadata,
108*90c8c64dSAndroid Build Coastguard Worker    );
109*90c8c64dSAndroid Build Coastguard Worker
110*90c8c64dSAndroid Build Coastguard Worker    if (initializeRealToElapsedTimeOffsetNs) {
111*90c8c64dSAndroid Build Coastguard Worker      const monotonicOffset = fileAndParsers
112*90c8c64dSAndroid Build Coastguard Worker        .find(
113*90c8c64dSAndroid Build Coastguard Worker          (fileAndParser) =>
114*90c8c64dSAndroid Build Coastguard Worker            fileAndParser.parser.getRealToMonotonicTimeOffsetNs() !== undefined,
115*90c8c64dSAndroid Build Coastguard Worker        )
116*90c8c64dSAndroid Build Coastguard Worker        ?.parser.getRealToMonotonicTimeOffsetNs();
117*90c8c64dSAndroid Build Coastguard Worker      if (monotonicOffset !== undefined) {
118*90c8c64dSAndroid Build Coastguard Worker        converter.setRealToMonotonicTimeOffsetNs(monotonicOffset);
119*90c8c64dSAndroid Build Coastguard Worker      }
120*90c8c64dSAndroid Build Coastguard Worker      const bootTimeOffset = fileAndParsers
121*90c8c64dSAndroid Build Coastguard Worker        .find(
122*90c8c64dSAndroid Build Coastguard Worker          (fileAndParser) =>
123*90c8c64dSAndroid Build Coastguard Worker            fileAndParser.parser.getRealToBootTimeOffsetNs() !== undefined,
124*90c8c64dSAndroid Build Coastguard Worker        )
125*90c8c64dSAndroid Build Coastguard Worker        ?.parser.getRealToBootTimeOffsetNs();
126*90c8c64dSAndroid Build Coastguard Worker      if (bootTimeOffset !== undefined) {
127*90c8c64dSAndroid Build Coastguard Worker        converter.setRealToBootTimeOffsetNs(bootTimeOffset);
128*90c8c64dSAndroid Build Coastguard Worker      }
129*90c8c64dSAndroid Build Coastguard Worker    }
130*90c8c64dSAndroid Build Coastguard Worker
131*90c8c64dSAndroid Build Coastguard Worker    return fileAndParsers.map((fileAndParser) => {
132*90c8c64dSAndroid Build Coastguard Worker      fileAndParser.parser.createTimestamps();
133*90c8c64dSAndroid Build Coastguard Worker      return fileAndParser.parser;
134*90c8c64dSAndroid Build Coastguard Worker    });
135*90c8c64dSAndroid Build Coastguard Worker  }
136*90c8c64dSAndroid Build Coastguard Worker
137*90c8c64dSAndroid Build Coastguard Worker  static async getPerfettoParser<T extends TraceType>(
138*90c8c64dSAndroid Build Coastguard Worker    traceType: T,
139*90c8c64dSAndroid Build Coastguard Worker    fixturePath: string,
140*90c8c64dSAndroid Build Coastguard Worker    withUTCOffset = false,
141*90c8c64dSAndroid Build Coastguard Worker  ): Promise<Parser<TraceEntryTypeMap[T]>> {
142*90c8c64dSAndroid Build Coastguard Worker    const parsers = await UnitTestUtils.getPerfettoParsers(
143*90c8c64dSAndroid Build Coastguard Worker      fixturePath,
144*90c8c64dSAndroid Build Coastguard Worker      withUTCOffset,
145*90c8c64dSAndroid Build Coastguard Worker    );
146*90c8c64dSAndroid Build Coastguard Worker    const parser = assertDefined(
147*90c8c64dSAndroid Build Coastguard Worker      parsers.find((parser) => parser.getTraceType() === traceType),
148*90c8c64dSAndroid Build Coastguard Worker    );
149*90c8c64dSAndroid Build Coastguard Worker    return parser as Parser<TraceEntryTypeMap[T]>;
150*90c8c64dSAndroid Build Coastguard Worker  }
151*90c8c64dSAndroid Build Coastguard Worker
152*90c8c64dSAndroid Build Coastguard Worker  static async getPerfettoParsers(
153*90c8c64dSAndroid Build Coastguard Worker    fixturePath: string,
154*90c8c64dSAndroid Build Coastguard Worker    withUTCOffset = false,
155*90c8c64dSAndroid Build Coastguard Worker  ): Promise<Array<Parser<object>>> {
156*90c8c64dSAndroid Build Coastguard Worker    const file = await UnitTestUtils.getFixtureFile(fixturePath);
157*90c8c64dSAndroid Build Coastguard Worker    const traceFile = new TraceFile(file);
158*90c8c64dSAndroid Build Coastguard Worker    const converter = UnitTestUtils.getTimestampConverter(withUTCOffset);
159*90c8c64dSAndroid Build Coastguard Worker    const parsers = await new PerfettoParserFactory().createParsers(
160*90c8c64dSAndroid Build Coastguard Worker      traceFile,
161*90c8c64dSAndroid Build Coastguard Worker      converter,
162*90c8c64dSAndroid Build Coastguard Worker      undefined,
163*90c8c64dSAndroid Build Coastguard Worker    );
164*90c8c64dSAndroid Build Coastguard Worker    parsers.forEach((parser) => {
165*90c8c64dSAndroid Build Coastguard Worker      converter.setRealToBootTimeOffsetNs(
166*90c8c64dSAndroid Build Coastguard Worker        assertDefined(parser.getRealToBootTimeOffsetNs()),
167*90c8c64dSAndroid Build Coastguard Worker      );
168*90c8c64dSAndroid Build Coastguard Worker      parser.createTimestamps();
169*90c8c64dSAndroid Build Coastguard Worker    });
170*90c8c64dSAndroid Build Coastguard Worker    return parsers;
171*90c8c64dSAndroid Build Coastguard Worker  }
172*90c8c64dSAndroid Build Coastguard Worker
173*90c8c64dSAndroid Build Coastguard Worker  static async getTracesParser(
174*90c8c64dSAndroid Build Coastguard Worker    filenames: string[],
175*90c8c64dSAndroid Build Coastguard Worker    withUTCOffset = false,
176*90c8c64dSAndroid Build Coastguard Worker  ): Promise<Parser<object>> {
177*90c8c64dSAndroid Build Coastguard Worker    const converter = UnitTestUtils.getTimestampConverter(withUTCOffset);
178*90c8c64dSAndroid Build Coastguard Worker    const legacyParsers = (
179*90c8c64dSAndroid Build Coastguard Worker      await Promise.all(
180*90c8c64dSAndroid Build Coastguard Worker        filenames.map(async (filename) =>
181*90c8c64dSAndroid Build Coastguard Worker          UnitTestUtils.getParsers(filename, converter, true),
182*90c8c64dSAndroid Build Coastguard Worker        ),
183*90c8c64dSAndroid Build Coastguard Worker      )
184*90c8c64dSAndroid Build Coastguard Worker    ).reduce((acc, cur) => acc.concat(cur), []);
185*90c8c64dSAndroid Build Coastguard Worker
186*90c8c64dSAndroid Build Coastguard Worker    const perfettoParsers = (
187*90c8c64dSAndroid Build Coastguard Worker      await Promise.all(
188*90c8c64dSAndroid Build Coastguard Worker        filenames.map(async (filename) =>
189*90c8c64dSAndroid Build Coastguard Worker          UnitTestUtils.getPerfettoParsers(filename),
190*90c8c64dSAndroid Build Coastguard Worker        ),
191*90c8c64dSAndroid Build Coastguard Worker      )
192*90c8c64dSAndroid Build Coastguard Worker    ).reduce((acc, cur) => acc.concat(cur), []);
193*90c8c64dSAndroid Build Coastguard Worker
194*90c8c64dSAndroid Build Coastguard Worker    const parsersArray = legacyParsers.concat(perfettoParsers);
195*90c8c64dSAndroid Build Coastguard Worker
196*90c8c64dSAndroid Build Coastguard Worker    const offset = parsersArray
197*90c8c64dSAndroid Build Coastguard Worker      .filter((parser) => parser.getRealToBootTimeOffsetNs() !== undefined)
198*90c8c64dSAndroid Build Coastguard Worker      .sort((a, b) =>
199*90c8c64dSAndroid Build Coastguard Worker        Number(
200*90c8c64dSAndroid Build Coastguard Worker          (a.getRealToBootTimeOffsetNs() ?? 0n) -
201*90c8c64dSAndroid Build Coastguard Worker            (b.getRealToBootTimeOffsetNs() ?? 0n),
202*90c8c64dSAndroid Build Coastguard Worker        ),
203*90c8c64dSAndroid Build Coastguard Worker      )
204*90c8c64dSAndroid Build Coastguard Worker      .at(-1)
205*90c8c64dSAndroid Build Coastguard Worker      ?.getRealToBootTimeOffsetNs();
206*90c8c64dSAndroid Build Coastguard Worker
207*90c8c64dSAndroid Build Coastguard Worker    if (offset !== undefined) {
208*90c8c64dSAndroid Build Coastguard Worker      converter.setRealToBootTimeOffsetNs(offset);
209*90c8c64dSAndroid Build Coastguard Worker    }
210*90c8c64dSAndroid Build Coastguard Worker
211*90c8c64dSAndroid Build Coastguard Worker    const traces = new Traces();
212*90c8c64dSAndroid Build Coastguard Worker    parsersArray.forEach((parser) => {
213*90c8c64dSAndroid Build Coastguard Worker      const trace = Trace.fromParser(parser);
214*90c8c64dSAndroid Build Coastguard Worker      traces.addTrace(trace);
215*90c8c64dSAndroid Build Coastguard Worker    });
216*90c8c64dSAndroid Build Coastguard Worker
217*90c8c64dSAndroid Build Coastguard Worker    const tracesParsers = await new TracesParserFactory().createParsers(
218*90c8c64dSAndroid Build Coastguard Worker      traces,
219*90c8c64dSAndroid Build Coastguard Worker      converter,
220*90c8c64dSAndroid Build Coastguard Worker    );
221*90c8c64dSAndroid Build Coastguard Worker    expect(tracesParsers.length)
222*90c8c64dSAndroid Build Coastguard Worker      .withContext(
223*90c8c64dSAndroid Build Coastguard Worker        `Should have been able to create a traces parser for [${filenames.join()}]`,
224*90c8c64dSAndroid Build Coastguard Worker      )
225*90c8c64dSAndroid Build Coastguard Worker      .toEqual(1);
226*90c8c64dSAndroid Build Coastguard Worker    return tracesParsers[0];
227*90c8c64dSAndroid Build Coastguard Worker  }
228*90c8c64dSAndroid Build Coastguard Worker
229*90c8c64dSAndroid Build Coastguard Worker  static getTimestampConverter(withUTCOffset = false): TimestampConverter {
230*90c8c64dSAndroid Build Coastguard Worker    return withUTCOffset
231*90c8c64dSAndroid Build Coastguard Worker      ? new TimestampConverter(TimestampConverterUtils.ASIA_TIMEZONE_INFO)
232*90c8c64dSAndroid Build Coastguard Worker      : new TimestampConverter(TimestampConverterUtils.UTC_TIMEZONE_INFO);
233*90c8c64dSAndroid Build Coastguard Worker  }
234*90c8c64dSAndroid Build Coastguard Worker
235*90c8c64dSAndroid Build Coastguard Worker  static async getWindowManagerState(index = 0): Promise<HierarchyTreeNode> {
236*90c8c64dSAndroid Build Coastguard Worker    return UnitTestUtils.getTraceEntry(
237*90c8c64dSAndroid Build Coastguard Worker      'traces/elapsed_and_real_timestamp/WindowManager.pb',
238*90c8c64dSAndroid Build Coastguard Worker      index,
239*90c8c64dSAndroid Build Coastguard Worker    );
240*90c8c64dSAndroid Build Coastguard Worker  }
241*90c8c64dSAndroid Build Coastguard Worker
242*90c8c64dSAndroid Build Coastguard Worker  static async getLayerTraceEntry(index = 0): Promise<HierarchyTreeNode> {
243*90c8c64dSAndroid Build Coastguard Worker    return await UnitTestUtils.getTraceEntry<HierarchyTreeNode>(
244*90c8c64dSAndroid Build Coastguard Worker      'traces/elapsed_timestamp/SurfaceFlinger.pb',
245*90c8c64dSAndroid Build Coastguard Worker      index,
246*90c8c64dSAndroid Build Coastguard Worker    );
247*90c8c64dSAndroid Build Coastguard Worker  }
248*90c8c64dSAndroid Build Coastguard Worker
249*90c8c64dSAndroid Build Coastguard Worker  static async getViewCaptureEntry(): Promise<HierarchyTreeNode> {
250*90c8c64dSAndroid Build Coastguard Worker    return await UnitTestUtils.getTraceEntry<HierarchyTreeNode>(
251*90c8c64dSAndroid Build Coastguard Worker      'traces/elapsed_and_real_timestamp/com.google.android.apps.nexuslauncher_0.vc',
252*90c8c64dSAndroid Build Coastguard Worker    );
253*90c8c64dSAndroid Build Coastguard Worker  }
254*90c8c64dSAndroid Build Coastguard Worker
255*90c8c64dSAndroid Build Coastguard Worker  static async getMultiDisplayLayerTraceEntry(): Promise<HierarchyTreeNode> {
256*90c8c64dSAndroid Build Coastguard Worker    return await UnitTestUtils.getTraceEntry<HierarchyTreeNode>(
257*90c8c64dSAndroid Build Coastguard Worker      'traces/elapsed_and_real_timestamp/SurfaceFlinger_multidisplay.pb',
258*90c8c64dSAndroid Build Coastguard Worker    );
259*90c8c64dSAndroid Build Coastguard Worker  }
260*90c8c64dSAndroid Build Coastguard Worker
261*90c8c64dSAndroid Build Coastguard Worker  static async getImeTraceEntries(): Promise<
262*90c8c64dSAndroid Build Coastguard Worker    [Map<TraceType, HierarchyTreeNode>, Map<TraceType, HierarchyTreeNode>]
263*90c8c64dSAndroid Build Coastguard Worker  > {
264*90c8c64dSAndroid Build Coastguard Worker    let surfaceFlingerEntry: HierarchyTreeNode | undefined;
265*90c8c64dSAndroid Build Coastguard Worker    {
266*90c8c64dSAndroid Build Coastguard Worker      const parser = (await UnitTestUtils.getParser(
267*90c8c64dSAndroid Build Coastguard Worker        'traces/ime/SurfaceFlinger_with_IME.pb',
268*90c8c64dSAndroid Build Coastguard Worker      )) as Parser<HierarchyTreeNode>;
269*90c8c64dSAndroid Build Coastguard Worker      surfaceFlingerEntry = await parser.getEntry(5);
270*90c8c64dSAndroid Build Coastguard Worker    }
271*90c8c64dSAndroid Build Coastguard Worker
272*90c8c64dSAndroid Build Coastguard Worker    let windowManagerEntry: HierarchyTreeNode | undefined;
273*90c8c64dSAndroid Build Coastguard Worker    {
274*90c8c64dSAndroid Build Coastguard Worker      const parser = (await UnitTestUtils.getParser(
275*90c8c64dSAndroid Build Coastguard Worker        'traces/ime/WindowManager_with_IME.pb',
276*90c8c64dSAndroid Build Coastguard Worker      )) as Parser<HierarchyTreeNode>;
277*90c8c64dSAndroid Build Coastguard Worker      windowManagerEntry = await parser.getEntry(2);
278*90c8c64dSAndroid Build Coastguard Worker    }
279*90c8c64dSAndroid Build Coastguard Worker
280*90c8c64dSAndroid Build Coastguard Worker    const entries = new Map<TraceType, HierarchyTreeNode>();
281*90c8c64dSAndroid Build Coastguard Worker    entries.set(
282*90c8c64dSAndroid Build Coastguard Worker      TraceType.INPUT_METHOD_CLIENTS,
283*90c8c64dSAndroid Build Coastguard Worker      await UnitTestUtils.getTraceEntry('traces/ime/InputMethodClients.pb'),
284*90c8c64dSAndroid Build Coastguard Worker    );
285*90c8c64dSAndroid Build Coastguard Worker    entries.set(
286*90c8c64dSAndroid Build Coastguard Worker      TraceType.INPUT_METHOD_MANAGER_SERVICE,
287*90c8c64dSAndroid Build Coastguard Worker      await UnitTestUtils.getTraceEntry(
288*90c8c64dSAndroid Build Coastguard Worker        'traces/ime/InputMethodManagerService.pb',
289*90c8c64dSAndroid Build Coastguard Worker      ),
290*90c8c64dSAndroid Build Coastguard Worker    );
291*90c8c64dSAndroid Build Coastguard Worker    entries.set(
292*90c8c64dSAndroid Build Coastguard Worker      TraceType.INPUT_METHOD_SERVICE,
293*90c8c64dSAndroid Build Coastguard Worker      await UnitTestUtils.getTraceEntry('traces/ime/InputMethodService.pb'),
294*90c8c64dSAndroid Build Coastguard Worker    );
295*90c8c64dSAndroid Build Coastguard Worker    entries.set(TraceType.SURFACE_FLINGER, surfaceFlingerEntry);
296*90c8c64dSAndroid Build Coastguard Worker    entries.set(TraceType.WINDOW_MANAGER, windowManagerEntry);
297*90c8c64dSAndroid Build Coastguard Worker
298*90c8c64dSAndroid Build Coastguard Worker    const secondEntries = new Map<TraceType, HierarchyTreeNode>();
299*90c8c64dSAndroid Build Coastguard Worker    secondEntries.set(
300*90c8c64dSAndroid Build Coastguard Worker      TraceType.INPUT_METHOD_CLIENTS,
301*90c8c64dSAndroid Build Coastguard Worker      await UnitTestUtils.getTraceEntry('traces/ime/InputMethodClients.pb', 1),
302*90c8c64dSAndroid Build Coastguard Worker    );
303*90c8c64dSAndroid Build Coastguard Worker    secondEntries.set(TraceType.SURFACE_FLINGER, surfaceFlingerEntry);
304*90c8c64dSAndroid Build Coastguard Worker    secondEntries.set(TraceType.WINDOW_MANAGER, windowManagerEntry);
305*90c8c64dSAndroid Build Coastguard Worker
306*90c8c64dSAndroid Build Coastguard Worker    return [entries, secondEntries];
307*90c8c64dSAndroid Build Coastguard Worker  }
308*90c8c64dSAndroid Build Coastguard Worker
309*90c8c64dSAndroid Build Coastguard Worker  static async getTraceEntry<T>(filename: string, index = 0) {
310*90c8c64dSAndroid Build Coastguard Worker    const parser = (await UnitTestUtils.getParser(filename)) as Parser<T>;
311*90c8c64dSAndroid Build Coastguard Worker    return parser.getEntry(index);
312*90c8c64dSAndroid Build Coastguard Worker  }
313*90c8c64dSAndroid Build Coastguard Worker
314*90c8c64dSAndroid Build Coastguard Worker  static timestampEqualityTester(first: any, second: any): boolean | undefined {
315*90c8c64dSAndroid Build Coastguard Worker    if (first instanceof Timestamp && second instanceof Timestamp) {
316*90c8c64dSAndroid Build Coastguard Worker      return UnitTestUtils.testTimestamps(first, second);
317*90c8c64dSAndroid Build Coastguard Worker    }
318*90c8c64dSAndroid Build Coastguard Worker    return undefined;
319*90c8c64dSAndroid Build Coastguard Worker  }
320*90c8c64dSAndroid Build Coastguard Worker
321*90c8c64dSAndroid Build Coastguard Worker  static checkSectionCollapseAndExpand<T>(
322*90c8c64dSAndroid Build Coastguard Worker    htmlElement: HTMLElement,
323*90c8c64dSAndroid Build Coastguard Worker    fixture: ComponentFixture<T>,
324*90c8c64dSAndroid Build Coastguard Worker    selector: string,
325*90c8c64dSAndroid Build Coastguard Worker    sectionTitle: string,
326*90c8c64dSAndroid Build Coastguard Worker  ) {
327*90c8c64dSAndroid Build Coastguard Worker    const section = assertDefined(htmlElement.querySelector(selector));
328*90c8c64dSAndroid Build Coastguard Worker    const collapseButton = assertDefined(
329*90c8c64dSAndroid Build Coastguard Worker      section.querySelector('collapsible-section-title button'),
330*90c8c64dSAndroid Build Coastguard Worker    ) as HTMLElement;
331*90c8c64dSAndroid Build Coastguard Worker    collapseButton.click();
332*90c8c64dSAndroid Build Coastguard Worker    fixture.detectChanges();
333*90c8c64dSAndroid Build Coastguard Worker    expect(section.classList).toContain('collapsed');
334*90c8c64dSAndroid Build Coastguard Worker    const collapsedSections = assertDefined(
335*90c8c64dSAndroid Build Coastguard Worker      htmlElement.querySelector('collapsed-sections'),
336*90c8c64dSAndroid Build Coastguard Worker    );
337*90c8c64dSAndroid Build Coastguard Worker    const collapsedSection = assertDefined(
338*90c8c64dSAndroid Build Coastguard Worker      collapsedSections.querySelector('.collapsed-section'),
339*90c8c64dSAndroid Build Coastguard Worker    ) as HTMLElement;
340*90c8c64dSAndroid Build Coastguard Worker    expect(collapsedSection.textContent).toContain(sectionTitle);
341*90c8c64dSAndroid Build Coastguard Worker    collapsedSection.click();
342*90c8c64dSAndroid Build Coastguard Worker    fixture.detectChanges();
343*90c8c64dSAndroid Build Coastguard Worker    UnitTestUtils.checkNoCollapsedSectionButtons(htmlElement);
344*90c8c64dSAndroid Build Coastguard Worker  }
345*90c8c64dSAndroid Build Coastguard Worker
346*90c8c64dSAndroid Build Coastguard Worker  static checkNoCollapsedSectionButtons(htmlElement: HTMLElement) {
347*90c8c64dSAndroid Build Coastguard Worker    const collapsedSections = assertDefined(
348*90c8c64dSAndroid Build Coastguard Worker      htmlElement.querySelector('collapsed-sections'),
349*90c8c64dSAndroid Build Coastguard Worker    );
350*90c8c64dSAndroid Build Coastguard Worker    expect(
351*90c8c64dSAndroid Build Coastguard Worker      collapsedSections.querySelectorAll('.collapsed-section').length,
352*90c8c64dSAndroid Build Coastguard Worker    ).toEqual(0);
353*90c8c64dSAndroid Build Coastguard Worker  }
354*90c8c64dSAndroid Build Coastguard Worker
355*90c8c64dSAndroid Build Coastguard Worker  static makeEmptyTrace<T extends TraceType>(
356*90c8c64dSAndroid Build Coastguard Worker    traceType: T,
357*90c8c64dSAndroid Build Coastguard Worker    descriptors: string[] = [],
358*90c8c64dSAndroid Build Coastguard Worker  ): Trace<TraceEntryTypeMap[T]> {
359*90c8c64dSAndroid Build Coastguard Worker    return new TraceBuilder<TraceEntryTypeMap[T]>()
360*90c8c64dSAndroid Build Coastguard Worker      .setEntries([])
361*90c8c64dSAndroid Build Coastguard Worker      .setTimestamps([])
362*90c8c64dSAndroid Build Coastguard Worker      .setDescriptors(descriptors)
363*90c8c64dSAndroid Build Coastguard Worker      .setType(traceType)
364*90c8c64dSAndroid Build Coastguard Worker      .build();
365*90c8c64dSAndroid Build Coastguard Worker  }
366*90c8c64dSAndroid Build Coastguard Worker
367*90c8c64dSAndroid Build Coastguard Worker  static makeSearchTraceSpies(
368*90c8c64dSAndroid Build Coastguard Worker    ts?: Timestamp,
369*90c8c64dSAndroid Build Coastguard Worker  ): [jasmine.SpyObj<QueryResult>, jasmine.SpyObj<RowIterator<Row>>] {
370*90c8c64dSAndroid Build Coastguard Worker    const spyQueryResult = jasmine.createSpyObj<QueryResult>('result', [
371*90c8c64dSAndroid Build Coastguard Worker      'numRows',
372*90c8c64dSAndroid Build Coastguard Worker      'columns',
373*90c8c64dSAndroid Build Coastguard Worker      'iter',
374*90c8c64dSAndroid Build Coastguard Worker    ]);
375*90c8c64dSAndroid Build Coastguard Worker    spyQueryResult.numRows.and.returnValue(1);
376*90c8c64dSAndroid Build Coastguard Worker    spyQueryResult.columns.and.returnValue(
377*90c8c64dSAndroid Build Coastguard Worker      ts === undefined ? ['property'] : ['ts', 'property'],
378*90c8c64dSAndroid Build Coastguard Worker    );
379*90c8c64dSAndroid Build Coastguard Worker
380*90c8c64dSAndroid Build Coastguard Worker    const spyIter = jasmine.createSpyObj<RowIterator<Row>>('iter', [
381*90c8c64dSAndroid Build Coastguard Worker      'valid',
382*90c8c64dSAndroid Build Coastguard Worker      'next',
383*90c8c64dSAndroid Build Coastguard Worker      'get',
384*90c8c64dSAndroid Build Coastguard Worker    ]);
385*90c8c64dSAndroid Build Coastguard Worker    if (ts) {
386*90c8c64dSAndroid Build Coastguard Worker      spyIter.get.withArgs('ts').and.returnValue(ts.getValueNs());
387*90c8c64dSAndroid Build Coastguard Worker    }
388*90c8c64dSAndroid Build Coastguard Worker    spyIter.get.withArgs('property').and.returnValue('test_value');
389*90c8c64dSAndroid Build Coastguard Worker    spyIter.valid.and.returnValue(true);
390*90c8c64dSAndroid Build Coastguard Worker    spyIter.next.and.callFake(() =>
391*90c8c64dSAndroid Build Coastguard Worker      assertDefined(spyIter).valid.and.returnValue(false),
392*90c8c64dSAndroid Build Coastguard Worker    );
393*90c8c64dSAndroid Build Coastguard Worker    spyQueryResult.iter.and.returnValue(spyIter);
394*90c8c64dSAndroid Build Coastguard Worker
395*90c8c64dSAndroid Build Coastguard Worker    return [spyQueryResult, spyIter];
396*90c8c64dSAndroid Build Coastguard Worker  }
397*90c8c64dSAndroid Build Coastguard Worker
398*90c8c64dSAndroid Build Coastguard Worker  static async runQueryAndGetResult(query: string): Promise<QueryResult> {
399*90c8c64dSAndroid Build Coastguard Worker    const tp = await TraceProcessorFactory.getSingleInstance();
400*90c8c64dSAndroid Build Coastguard Worker    return tp.query(query).waitAllRows();
401*90c8c64dSAndroid Build Coastguard Worker  }
402*90c8c64dSAndroid Build Coastguard Worker
403*90c8c64dSAndroid Build Coastguard Worker  private static testTimestamps(
404*90c8c64dSAndroid Build Coastguard Worker    timestamp: Timestamp,
405*90c8c64dSAndroid Build Coastguard Worker    expectedTimestamp: Timestamp,
406*90c8c64dSAndroid Build Coastguard Worker  ): boolean {
407*90c8c64dSAndroid Build Coastguard Worker    if (timestamp.format() !== expectedTimestamp.format()) return false;
408*90c8c64dSAndroid Build Coastguard Worker    if (timestamp.getValueNs() !== expectedTimestamp.getValueNs()) {
409*90c8c64dSAndroid Build Coastguard Worker      return false;
410*90c8c64dSAndroid Build Coastguard Worker    }
411*90c8c64dSAndroid Build Coastguard Worker    return true;
412*90c8c64dSAndroid Build Coastguard Worker  }
413*90c8c64dSAndroid Build Coastguard Worker}
414*90c8c64dSAndroid Build Coastguard Worker
415*90c8c64dSAndroid Build Coastguard Workerexport {UnitTestUtils};
416