1/* 2 * Copyright (C) 2022 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 {TracesUtils} from 'test/unit/traces_utils'; 19import {UnitTestUtils} from 'test/unit/utils'; 20import {TraceFile} from 'trace/trace_file'; 21import {TraceType} from 'trace/trace_type'; 22import {TracePipeline} from './trace_pipeline'; 23 24describe('TracePipeline', () => { 25 let validSfTraceFile: TraceFile; 26 let validWmTraceFile: TraceFile; 27 let tracePipeline: TracePipeline; 28 29 beforeEach(async () => { 30 validSfTraceFile = new TraceFile( 31 await UnitTestUtils.getFixtureFile('traces/elapsed_and_real_timestamp/SurfaceFlinger.pb') 32 ); 33 validWmTraceFile = new TraceFile( 34 await UnitTestUtils.getFixtureFile('traces/elapsed_and_real_timestamp/WindowManager.pb') 35 ); 36 tracePipeline = new TracePipeline(); 37 }); 38 39 it('can load valid trace files', async () => { 40 expect(tracePipeline.getTraces().getSize()).toEqual(0); 41 42 await loadValidSfWmTraces(); 43 44 expect(tracePipeline.getTraces().getSize()).toEqual(2); 45 46 const traceEntries = await TracesUtils.extractEntries(tracePipeline.getTraces()); 47 expect(traceEntries.get(TraceType.WINDOW_MANAGER)?.length).toBeGreaterThan(0); 48 expect(traceEntries.get(TraceType.SURFACE_FLINGER)?.length).toBeGreaterThan(0); 49 }); 50 51 it('can load a new file without dropping already-loaded traces', async () => { 52 expect(tracePipeline.getTraces().getSize()).toEqual(0); 53 54 await tracePipeline.loadTraceFiles([validSfTraceFile]); 55 expect(tracePipeline.getTraces().getSize()).toEqual(1); 56 57 await tracePipeline.loadTraceFiles([validWmTraceFile]); 58 expect(tracePipeline.getTraces().getSize()).toEqual(2); 59 60 await tracePipeline.loadTraceFiles([validWmTraceFile]); // ignored (duplicated) 61 expect(tracePipeline.getTraces().getSize()).toEqual(2); 62 }); 63 64 it('can load bugreport and ignores non-trace dirs', async () => { 65 expect(tracePipeline.getTraces().getSize()).toEqual(0); 66 67 // Could be any file, we just need an instance of File to be used as a fake bugreport archive 68 const bugreportArchive = await UnitTestUtils.getFixtureFile( 69 'bugreports/bugreport_stripped.zip' 70 ); 71 72 const bugreportFiles = [ 73 new TraceFile( 74 await UnitTestUtils.getFixtureFile('bugreports/main_entry.txt', 'main_entry.txt'), 75 bugreportArchive 76 ), 77 new TraceFile( 78 await UnitTestUtils.getFixtureFile( 79 'bugreports/bugreport-codename_beta-UPB2.230407.019-2023-05-30-14-33-48.txt', 80 'bugreport-codename_beta-UPB2.230407.019-2023-05-30-14-33-48.txt' 81 ), 82 bugreportArchive 83 ), 84 new TraceFile( 85 await UnitTestUtils.getFixtureFile( 86 'traces/elapsed_and_real_timestamp/SurfaceFlinger.pb', 87 'FS/data/misc/wmtrace/surface_flinger.bp' 88 ), 89 bugreportArchive 90 ), 91 new TraceFile( 92 await UnitTestUtils.getFixtureFile( 93 'traces/elapsed_and_real_timestamp/Transactions.pb', 94 'FS/data/misc/wmtrace/transactions.bp' 95 ), 96 bugreportArchive 97 ), 98 new TraceFile( 99 await UnitTestUtils.getFixtureFile( 100 'traces/elapsed_and_real_timestamp/WindowManager.pb', 101 'proto/window_CRITICAL.proto' 102 ), 103 bugreportArchive 104 ), 105 new TraceFile( 106 await UnitTestUtils.getFixtureFile( 107 'traces/elapsed_and_real_timestamp/wm_transition_trace.pb', 108 'FS/data/misc/ignored-dir/wm_transition_trace.bp' 109 ), 110 bugreportArchive 111 ), 112 ]; 113 114 // Corner case: 115 // A plain trace file is loaded along the bugreport -> trace file must not be ignored 116 // 117 // Note: 118 // The even weirder corner case where two bugreports are loaded at the same time is 119 // currently not properly handled. 120 const plainTraceFile = new TraceFile( 121 await UnitTestUtils.getFixtureFile( 122 'traces/elapsed_and_real_timestamp/InputMethodClients.pb', 123 'would-be-ignored-if-was-part-of-bugreport/input_method_clients.pb' 124 ) 125 ); 126 127 const mergedFiles = bugreportFiles.concat([plainTraceFile]); 128 const errors = await tracePipeline.loadTraceFiles(mergedFiles); 129 expect(errors.length).toEqual(0); 130 await tracePipeline.buildTraces(); 131 const traces = tracePipeline.getTraces(); 132 133 expect(traces.getTrace(TraceType.SURFACE_FLINGER)).toBeDefined(); 134 expect(traces.getTrace(TraceType.TRANSACTIONS)).toBeDefined(); 135 expect(traces.getTrace(TraceType.WM_TRANSITION)).toBeUndefined(); // ignored 136 expect(traces.getTrace(TraceType.INPUT_METHOD_CLIENTS)).toBeDefined(); 137 expect(traces.getTrace(TraceType.WINDOW_MANAGER)).toBeDefined(); 138 }); 139 140 it('is robust to invalid trace files', async () => { 141 const invalidTraceFiles = [ 142 new TraceFile(await UnitTestUtils.getFixtureFile('winscope_homepage.png')), 143 ]; 144 145 const errors = await tracePipeline.loadTraceFiles(invalidTraceFiles); 146 await tracePipeline.buildTraces(); 147 expect(errors.length).toEqual(1); 148 expect(tracePipeline.getTraces().getSize()).toEqual(0); 149 }); 150 151 it('is robust to mixed valid and invalid trace files', async () => { 152 expect(tracePipeline.getTraces().getSize()).toEqual(0); 153 const files = [ 154 new TraceFile(await UnitTestUtils.getFixtureFile('winscope_homepage.png')), 155 new TraceFile(await UnitTestUtils.getFixtureFile('traces/dump_WindowManager.pb')), 156 ]; 157 const errors = await tracePipeline.loadTraceFiles(files); 158 await tracePipeline.buildTraces(); 159 expect(tracePipeline.getTraces().getSize()).toEqual(1); 160 expect(errors.length).toEqual(1); 161 }); 162 163 it('is robust to trace files with no entries', async () => { 164 const traceFilesWithNoEntries = [ 165 new TraceFile(await UnitTestUtils.getFixtureFile('traces/no_entries_InputMethodClients.pb')), 166 ]; 167 168 const errors = await tracePipeline.loadTraceFiles(traceFilesWithNoEntries); 169 await tracePipeline.buildTraces(); 170 171 expect(errors.length).toEqual(0); 172 173 expect(tracePipeline.getTraces().getSize()).toEqual(1); 174 }); 175 176 it('can remove traces', async () => { 177 await loadValidSfWmTraces(); 178 expect(tracePipeline.getTraces().getSize()).toEqual(2); 179 180 const sfTrace = assertDefined(tracePipeline.getTraces().getTrace(TraceType.SURFACE_FLINGER)); 181 const wmTrace = assertDefined(tracePipeline.getTraces().getTrace(TraceType.WINDOW_MANAGER)); 182 183 tracePipeline.removeTrace(sfTrace); 184 await tracePipeline.buildTraces(); 185 expect(tracePipeline.getTraces().getSize()).toEqual(1); 186 187 tracePipeline.removeTrace(wmTrace); 188 await tracePipeline.buildTraces(); 189 expect(tracePipeline.getTraces().getSize()).toEqual(0); 190 }); 191 192 it('gets loaded traces', async () => { 193 await loadValidSfWmTraces(); 194 195 const traces = tracePipeline.getTraces(); 196 expect(traces.getSize()).toEqual(2); 197 198 const actualTraceTypes = new Set(traces.mapTrace((trace) => trace.type)); 199 const expectedTraceTypes = new Set([TraceType.SURFACE_FLINGER, TraceType.WINDOW_MANAGER]); 200 expect(actualTraceTypes).toEqual(expectedTraceTypes); 201 202 const sfTrace = assertDefined(traces.getTrace(TraceType.SURFACE_FLINGER)); 203 expect(sfTrace.getDescriptors().length).toBeGreaterThan(0); 204 }); 205 206 it('builds traces', async () => { 207 await loadValidSfWmTraces(); 208 const traces = tracePipeline.getTraces(); 209 210 expect(traces.getTrace(TraceType.SURFACE_FLINGER)).toBeDefined(); 211 expect(traces.getTrace(TraceType.WINDOW_MANAGER)).toBeDefined(); 212 }); 213 214 it('gets screenrecording data', async () => { 215 const traceFiles = [ 216 new TraceFile( 217 await UnitTestUtils.getFixtureFile( 218 'traces/elapsed_and_real_timestamp/screen_recording_metadata_v2.mp4' 219 ) 220 ), 221 ]; 222 await tracePipeline.loadTraceFiles(traceFiles); 223 await tracePipeline.buildTraces(); 224 225 const video = await tracePipeline.getScreenRecordingVideo(); 226 expect(video).toBeDefined(); 227 expect(video!.size).toBeGreaterThan(0); 228 }); 229 230 it('can be cleared', async () => { 231 await loadValidSfWmTraces(); 232 expect(tracePipeline.getTraces().getSize()).toBeGreaterThan(0); 233 234 tracePipeline.clear(); 235 expect(tracePipeline.getTraces().getSize()).toEqual(0); 236 }); 237 238 const loadValidSfWmTraces = async () => { 239 const traceFiles = [validSfTraceFile, validWmTraceFile]; 240 const errors = await tracePipeline.loadTraceFiles(traceFiles); 241 expect(errors.length).toEqual(0); 242 await tracePipeline.buildTraces(); 243 }; 244}); 245