1/* 2 * Copyright (C) 2025 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 { 18 AdbDeviceConnectionListener, 19 AdbDeviceState, 20} from 'trace_collection/adb/adb_device_connection'; 21import {MockAdbDeviceConnection} from 'trace_collection/mock/mock_adb_device_connection'; 22import {AdbFileIdentifier, TraceTarget} from 'trace_collection/trace_target'; 23import {TracingSession} from './tracing_session'; 24import {WINSCOPE_BACKUP_DIR} from './winscope_backup_dir'; 25 26describe('TracingSession', () => { 27 const listener: AdbDeviceConnectionListener = { 28 onError: jasmine.createSpy(), 29 onConnectionStateChange: jasmine.createSpy(), 30 onAvailableTracesChange: jasmine.createSpy(), 31 }; 32 const mockDevice = new MockAdbDeviceConnection( 33 '35562', 34 'Pixel 6', 35 AdbDeviceState.AVAILABLE, 36 listener, 37 ); 38 const fileIdentifiers = [ 39 new AdbFileIdentifier('test path 1', ['matcher'], 'saved file 1'), 40 new AdbFileIdentifier('test path 2', ['matcher'], 'saved file 2'), 41 ]; 42 const sessionName = 'TestSession'; 43 const stopCmd = 'test stop cmd'; 44 const startCmd = 'test start cmd'; 45 const setupCmds = ['setup1', 'setup2']; 46 let session: TracingSession; 47 let target: TraceTarget; 48 let startTraceSpy: jasmine.Spy; 49 let endTraceSpy: jasmine.Spy; 50 let moveFilesSpy: jasmine.Spy; 51 let runShellCmdSpy: jasmine.Spy; 52 let findFilesSpy: jasmine.Spy; 53 54 beforeEach(() => { 55 target = new TraceTarget( 56 sessionName, 57 setupCmds, 58 startCmd, 59 stopCmd, 60 fileIdentifiers, 61 ); 62 session = new TracingSession(target); 63 startTraceSpy = spyOn(mockDevice, 'startTrace'); 64 endTraceSpy = spyOn(mockDevice, 'endTrace'); 65 runShellCmdSpy = spyOn(mockDevice, 'runShellCommand'); 66 findFilesSpy = spyOn(mockDevice, 'findFiles').and.returnValue( 67 Promise.resolve(['file']), 68 ); 69 moveFilesSpy = spyOn(session, 'moveFiles').and.callThrough(); 70 }); 71 72 it('starts traces', async () => { 73 await session.start(mockDevice); 74 expect(runShellCmdSpy.calls.allArgs()).toEqual([['setup1'], ['setup2']]); 75 expect(startTraceSpy).toHaveBeenCalledOnceWith(target); 76 }); 77 78 it('stops traces and moves files', async () => { 79 await session.stop(mockDevice); 80 checkTraceStopSpies(0); 81 await session.start(mockDevice); 82 await session.stop(mockDevice); 83 checkTraceStopSpies(1, [target]); 84 }); 85 86 it('stops traces on destroy', async () => { 87 await session.onDestroy(mockDevice); 88 checkTraceStopSpies(0); 89 await session.start(mockDevice); 90 checkTraceStopSpies(0); 91 await session.onDestroy(mockDevice); 92 checkTraceStopSpies(1); 93 }); 94 95 it('dumps states', async () => { 96 await session.dump(mockDevice); 97 expect(runShellCmdSpy.calls.allArgs()).toEqual([ 98 ['setup1'], 99 ['setup2'], 100 [startCmd], 101 ]); 102 }); 103 104 it('moves files', async () => { 105 await session.moveFiles(mockDevice); 106 expect(findFilesSpy.calls.allArgs()).toEqual([ 107 ['test path 1', ['matcher']], 108 ['test path 2', ['matcher']], 109 ]); 110 expect(runShellCmdSpy.calls.allArgs()).toEqual([ 111 [ 112 `su root [ ! -f file ] || su root mv file ${WINSCOPE_BACKUP_DIR}saved file 1`, 113 ], 114 [ 115 `su root [ ! -f file ] || su root mv file ${WINSCOPE_BACKUP_DIR}saved file 2`, 116 ], 117 ]); 118 }); 119 120 it('handles error in move command', async () => { 121 runShellCmdSpy 122 .withArgs( 123 `su root [ ! -f file ] || su root mv file ${WINSCOPE_BACKUP_DIR}saved file 1`, 124 ) 125 .and.throwError(new Error()); 126 await expectAsync(session.moveFiles(mockDevice)).toBeResolved(); 127 }); 128 129 function checkTraceStopSpies(times: number, endArgs?: TraceTarget[]) { 130 expect(endTraceSpy).toHaveBeenCalledTimes(times); 131 expect(moveFilesSpy).toHaveBeenCalledTimes(times); 132 if (endArgs) { 133 expect(endTraceSpy).toHaveBeenCalledWith(...endArgs); 134 } 135 } 136}); 137