1// Copyright (C) 2018 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import {dingus} from 'dingusjs'; 16 17import {assertExists} from '../base/logging'; 18import {TraceConfig} from '../common/protos'; 19import {createEmptyRecordConfig, RecordConfig} from '../common/state'; 20 21import {App} from './globals'; 22import {genConfigProto, RecordController, toPbtxt} from './record_controller'; 23 24test('encodeConfig', () => { 25 const config = createEmptyRecordConfig(); 26 config.durationSeconds = 10; 27 const result = 28 TraceConfig.decode(genConfigProto(config, {os: 'Q', name: 'Android Q'})); 29 expect(result.durationMs).toBe(10000); 30}); 31 32test('SysConfig', () => { 33 const config = createEmptyRecordConfig(); 34 config.cpuSyscall = true; 35 const result = 36 TraceConfig.decode(genConfigProto(config, {os: 'Q', name: 'Android Q'})); 37 const sources = assertExists(result.dataSources); 38 const srcConfig = assertExists(sources[0].config); 39 const ftraceConfig = assertExists(srcConfig.ftraceConfig); 40 const ftraceEvents = assertExists(ftraceConfig.ftraceEvents); 41 expect(ftraceEvents.includes('raw_syscalls/sys_enter')).toBe(true); 42 expect(ftraceEvents.includes('raw_syscalls/sys_exit')).toBe(true); 43}); 44 45test('toPbtxt', () => { 46 const config = { 47 durationMs: 1000, 48 maxFileSizeBytes: 43, 49 buffers: [ 50 { 51 sizeKb: 42, 52 }, 53 ], 54 dataSources: [{ 55 config: { 56 name: 'linux.ftrace', 57 targetBuffer: 1, 58 ftraceConfig: { 59 ftraceEvents: ['sched_switch', 'print'], 60 }, 61 }, 62 }], 63 producers: [ 64 { 65 producerName: 'perfetto.traced_probes', 66 }, 67 ], 68 }; 69 70 const text = toPbtxt(TraceConfig.encode(config).finish()); 71 72 expect(text).toEqual(`buffers: { 73 size_kb: 42 74} 75data_sources: { 76 config { 77 name: "linux.ftrace" 78 target_buffer: 1 79 ftrace_config { 80 ftrace_events: "sched_switch" 81 ftrace_events: "print" 82 } 83 } 84} 85duration_ms: 1000 86producers: { 87 producer_name: "perfetto.traced_probes" 88} 89max_file_size_bytes: 43 90`); 91}); 92 93test('RecordController', () => { 94 const app = dingus<App>('globals'); 95 (app.state.recordConfig as RecordConfig) = createEmptyRecordConfig(); 96 const m: MessageChannel = dingus<MessageChannel>('extensionPort'); 97 const controller = new RecordController({app, extensionPort: m.port1}); 98 controller.run(); 99 controller.run(); 100 controller.run(); 101 // tslint:disable-next-line no-any 102 const calls = app.calls.filter((call: any) => call[0] === 'publish()'); 103 expect(calls.length).toBe(1); 104 // TODO(hjd): Fix up dingus to have a more sensible API. 105 expect(calls[0][1][0]).toEqual('TrackData'); 106}); 107 108test('ChromeConfig', () => { 109 const config = createEmptyRecordConfig(); 110 config.ipcFlows = true; 111 config.jsExecution = true; 112 config.mode = 'STOP_WHEN_FULL'; 113 const result = 114 TraceConfig.decode(genConfigProto(config, {os: 'C', name: 'Chrome'})); 115 const sources = assertExists(result.dataSources); 116 117 const traceConfigSource = assertExists(sources[0].config); 118 expect(traceConfigSource.name).toBe('org.chromium.trace_event'); 119 const chromeConfig = assertExists(traceConfigSource.chromeConfig); 120 const traceConfig = assertExists(chromeConfig.traceConfig); 121 122 const metadataConfigSource = assertExists(sources[1].config); 123 expect(metadataConfigSource.name).toBe('org.chromium.trace_metadata'); 124 const chromeConfigM = assertExists(metadataConfigSource.chromeConfig); 125 const traceConfigM = assertExists(chromeConfigM.traceConfig); 126 127 const expectedTraceConfig = '{"record_mode":"record-until-full",' + 128 '"included_categories":' + 129 '["toplevel","disabled-by-default-ipc.flow","mojom","v8"],' + 130 '"memory_dump_config":{}}'; 131 expect(traceConfigM).toEqual(expectedTraceConfig); 132 expect(traceConfig).toEqual(expectedTraceConfig); 133}); 134 135test('ChromeMemoryConfig', () => { 136 const config = createEmptyRecordConfig(); 137 config.chromeCategoriesSelected = ['disabled-by-default-memory-infra']; 138 const result = 139 TraceConfig.decode(genConfigProto(config, {os: 'C', name: 'Chrome'})); 140 const sources = assertExists(result.dataSources); 141 142 const traceConfigSource = assertExists(sources[0].config); 143 expect(traceConfigSource.name).toBe('org.chromium.trace_event'); 144 const chromeConfig = assertExists(traceConfigSource.chromeConfig); 145 const traceConfig = assertExists(chromeConfig.traceConfig); 146 147 const metadataConfigSource = assertExists(sources[1].config); 148 expect(metadataConfigSource.name).toBe('org.chromium.trace_metadata'); 149 const chromeConfigM = assertExists(metadataConfigSource.chromeConfig); 150 const traceConfigM = assertExists(chromeConfigM.traceConfig); 151 152 const expectedTraceConfig = '{"record_mode":"record-until-full",' + 153 '"included_categories":["disabled-by-default-memory-infra"],' + 154 '"memory_dump_config":{"triggers":' + 155 '[{"mode":"detailed","periodic_interval_ms":10000}]}}'; 156 expect(traceConfigM).toEqual(expectedTraceConfig); 157 expect(traceConfig).toEqual(expectedTraceConfig); 158}); 159 160test('ChromeConfigRingBuffer', () => { 161 const config = createEmptyRecordConfig(); 162 config.ipcFlows = true; 163 config.jsExecution = true; 164 config.mode = 'RING_BUFFER'; 165 const result = 166 TraceConfig.decode(genConfigProto(config, {os: 'C', name: 'Chrome'})); 167 const sources = assertExists(result.dataSources); 168 169 const traceConfigSource = assertExists(sources[0].config); 170 expect(traceConfigSource.name).toBe('org.chromium.trace_event'); 171 const chromeConfig = assertExists(traceConfigSource.chromeConfig); 172 const traceConfig = assertExists(chromeConfig.traceConfig); 173 174 const metadataConfigSource = assertExists(sources[1].config); 175 expect(metadataConfigSource.name).toBe('org.chromium.trace_metadata'); 176 const chromeConfigM = assertExists(metadataConfigSource.chromeConfig); 177 const traceConfigM = assertExists(chromeConfigM.traceConfig); 178 179 const expectedTraceConfig = '{"record_mode":"record-continuously",' + 180 '"included_categories":' + 181 '["toplevel","disabled-by-default-ipc.flow","mojom","v8"],' + 182 '"memory_dump_config":{}}'; 183 expect(traceConfigM).toEqual(expectedTraceConfig); 184 expect(traceConfig).toEqual(expectedTraceConfig); 185}); 186 187 188test('ChromeConfigLongTrace', () => { 189 const config = createEmptyRecordConfig(); 190 config.ipcFlows = true; 191 config.jsExecution = true; 192 config.mode = 'RING_BUFFER'; 193 const result = 194 TraceConfig.decode(genConfigProto(config, {os: 'C', name: 'Chrome'})); 195 const sources = assertExists(result.dataSources); 196 197 const traceConfigSource = assertExists(sources[0].config); 198 expect(traceConfigSource.name).toBe('org.chromium.trace_event'); 199 const chromeConfig = assertExists(traceConfigSource.chromeConfig); 200 const traceConfig = assertExists(chromeConfig.traceConfig); 201 202 const metadataConfigSource = assertExists(sources[1].config); 203 expect(metadataConfigSource.name).toBe('org.chromium.trace_metadata'); 204 const chromeConfigM = assertExists(metadataConfigSource.chromeConfig); 205 const traceConfigM = assertExists(chromeConfigM.traceConfig); 206 207 const expectedTraceConfig = '{"record_mode":"record-continuously",' + 208 '"included_categories":' + 209 '["toplevel","disabled-by-default-ipc.flow","mojom","v8"],' + 210 '"memory_dump_config":{}}'; 211 expect(traceConfigM).toEqual(expectedTraceConfig); 212 expect(traceConfig).toEqual(expectedTraceConfig); 213}); 214 215test('ChromeConfigToPbtxt', () => { 216 const config = { 217 dataSources: [{ 218 config: { 219 name: 'org.chromium.trace_event', 220 chromeConfig: 221 {traceConfig: JSON.stringify({included_categories: ['v8']})}, 222 }, 223 }], 224 }; 225 const text = toPbtxt(TraceConfig.encode(config).finish()); 226 227 expect(text).toEqual(`data_sources: { 228 config { 229 name: "org.chromium.trace_event" 230 chrome_config { 231 trace_config: "{\\"included_categories\\":[\\"v8\\"]}" 232 } 233 } 234} 235`); 236}); 237