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