1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 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 */ 15 16import * as fs from 'fs'; 17import * as path from 'path'; 18import { 19 PerfMode, 20 TimeAndMemTimeTracker, 21 clearTimeAndMemPrinterData, 22 configurePerformancePrinter, 23 disablePrinterTimeAndMemConfig, 24 enableTimeAndMemoryPrint, 25 endSingleFileForMoreTimeEvent, 26 getObfuscationCacheDir, 27 getMemoryPerformanceData, 28 getTimePerformanceData, 29 initPerformanceTimeAndMemPrinter, 30 initPrinterTimeAndMemConfig, 31 startSingleFileForMoreTimeEvent, 32 writeTimeAndMemoryPerformanceData, 33} from '../../../src/utils/PrinterTimeAndMemUtils'; 34import { expect } from 'chai'; 35import { performanceTimeAndMemPrinter } from '../../../src/ArkObfuscator'; 36import { printerTimeAndMemDataConfig } from '../../../src/initialization/Initializer'; 37 38describe('test Cases for <PrinterTimAndMemUtils>.', function () { 39 beforeEach(() => { 40 performanceTimeAndMemPrinter.filesPrinter = new TimeAndMemTimeTracker(); 41 performanceTimeAndMemPrinter.singleFilePrinter = new TimeAndMemTimeTracker(); 42 }); 43 44 describe('Tester Cases for <TimeTimeAndMemTracker>.', function () { 45 let printer: TimeAndMemTimeTracker; 46 47 beforeEach(() => { 48 printer = new TimeAndMemTimeTracker(); 49 }); 50 51 describe('Tester Cases for <startEvent>', () => { 52 /** test for startEvent */ 53 it('Tester: <start test event> case for TimeTimeAndMemTracker#startEvent', () => { 54 const eventName = 'test event'; 55 printer.startEvent(eventName); 56 const eventStack = printer.getEventStack(); 57 const event = eventStack.find((e) => e.eventName === eventName); 58 expect(event?.data.endMemory).to.equal(0); 59 }); 60 }); 61 62 describe('Tester Cases for <endEvent>', () => { 63 /** test for endEvent */ 64 it('should throw an error if the event has not started', function () { 65 printer.startEvent('testEvent'); 66 printer.endEvent('testEvent'); 67 expect(() => printer.endEvent('unstartedEvent')).to.throw(`Event stack is empty`); 68 }); 69 }); 70 }); 71 72 describe('Tester Cases for <initPerformanceTimeAndMemPrinter>', () => { 73 it('should block performance printer when mTimeAndMemPrinter is false', () => { 74 printerTimeAndMemDataConfig.mTimeAndMemPrinter = false; 75 performanceTimeAndMemPrinter.singleFilePrinter = new TimeAndMemTimeTracker(); 76 performanceTimeAndMemPrinter.filesPrinter = new TimeAndMemTimeTracker(); 77 78 initPerformanceTimeAndMemPrinter(); 79 80 expect(performanceTimeAndMemPrinter.singleFilePrinter).to.be.undefined; 81 expect(performanceTimeAndMemPrinter.filesPrinter).to.be.undefined; 82 }); 83 84 it('should not block performance printer when mTimeAndMemPrinter is true', () => { 85 printerTimeAndMemDataConfig.mTimeAndMemPrinter = true; 86 performanceTimeAndMemPrinter.singleFilePrinter = new TimeAndMemTimeTracker(); 87 performanceTimeAndMemPrinter.filesPrinter = new TimeAndMemTimeTracker(); 88 89 initPerformanceTimeAndMemPrinter(); 90 91 expect(performanceTimeAndMemPrinter.singleFilePrinter).to.not.be.undefined; 92 expect(performanceTimeAndMemPrinter.filesPrinter).to.not.be.undefined; 93 }); 94 }); 95 96 describe('Tester Cases for <configurePerformancePrinter>', () => { 97 it('should configure performance printer for advanced mode', () => { 98 printerTimeAndMemDataConfig.mTimeAndMemPrinter = false; 99 performanceTimeAndMemPrinter.singleFilePrinter = undefined; 100 performanceTimeAndMemPrinter.filesPrinter = undefined; 101 102 configurePerformancePrinter(PerfMode.ADVANCED); 103 104 expect(performanceTimeAndMemPrinter.singleFilePrinter).to.not.be.undefined; 105 expect(performanceTimeAndMemPrinter.filesPrinter).to.not.be.undefined; 106 expect(printerTimeAndMemDataConfig.mTimeAndMemPrinter).to.be.true; 107 }); 108 109 it('should block performance printer for normal mode', () => { 110 performanceTimeAndMemPrinter.singleFilePrinter = new TimeAndMemTimeTracker(); 111 performanceTimeAndMemPrinter.filesPrinter = new TimeAndMemTimeTracker(); 112 113 configurePerformancePrinter(PerfMode.NORMAL); 114 115 expect(performanceTimeAndMemPrinter.singleFilePrinter).to.be.undefined; 116 expect(performanceTimeAndMemPrinter.filesPrinter).to.be.undefined; 117 }); 118 }); 119 120 describe('Tester Cases for <clearTimeAndMemPrinterData>', () => { 121 it('start a clearTimeAndMemPrinterData event', () => { 122 if (performanceTimeAndMemPrinter.filesPrinter) { 123 performanceTimeAndMemPrinter.filesPrinter.timeDataArr.push({ 124 name: 'test', 125 ph: 'X', 126 pid: 1, 127 tid: 1, 128 ts: 5, 129 dur: 5, 130 }); 131 performanceTimeAndMemPrinter.filesPrinter.memoryDataArr.push({ 132 name: 'test', 133 startMemory: '5MB', 134 endMemory: '5MB', 135 }); 136 } 137 if (performanceTimeAndMemPrinter.singleFilePrinter) { 138 performanceTimeAndMemPrinter.singleFilePrinter.timeDataArr.push({ 139 name: 'test', 140 ph: 'X', 141 pid: 1, 142 tid: 1, 143 ts: 5, 144 dur: 5, 145 }); 146 performanceTimeAndMemPrinter.singleFilePrinter.memoryDataArr.push({ 147 name: 'test', 148 startMemory: '5MB', 149 endMemory: '5MB', 150 }); 151 } 152 153 clearTimeAndMemPrinterData(); 154 155 expect(performanceTimeAndMemPrinter.filesPrinter?.timeDataArr.length).to.equal(0); 156 expect(performanceTimeAndMemPrinter.filesPrinter?.memoryDataArr.length).to.equal(0); 157 expect(performanceTimeAndMemPrinter.singleFilePrinter?.timeDataArr.length).to.equal(0); 158 expect(performanceTimeAndMemPrinter.singleFilePrinter?.memoryDataArr.length).to.equal(0); 159 }); 160 161 it('start a clearTimeAndMemPrinterData event is not set', () => { 162 performanceTimeAndMemPrinter.filesPrinter = undefined; 163 performanceTimeAndMemPrinter.singleFilePrinter = undefined; 164 clearTimeAndMemPrinterData(); 165 expect(performanceTimeAndMemPrinter.filesPrinter === undefined).to.be.true; 166 expect(performanceTimeAndMemPrinter.singleFilePrinter === undefined).to.be.true; 167 }); 168 }); 169 170 describe('Tester Cases for <initPrinterTimeAndMemConfig>', () => { 171 it('start a initPrinterTimeAndMemConfig', () => { 172 printerTimeAndMemDataConfig.mTimeAndMemPrinter = false; 173 initPrinterTimeAndMemConfig(); 174 expect(printerTimeAndMemDataConfig.mTimeAndMemPrinter).to.be.true; 175 }); 176 }); 177 178 describe('Tester Cases for <disablePrinterTimeAndMemConfig>', () => { 179 it('start a disablePrinterTimeAndMemConfig', () => { 180 printerTimeAndMemDataConfig.mTimeAndMemPrinter = true; 181 disablePrinterTimeAndMemConfig(); 182 expect(printerTimeAndMemDataConfig.mTimeAndMemPrinter).to.be.false; 183 }); 184 }); 185 186 describe('Tester Cases for <startSingleFileForMoreTimeEvent>', () => { 187 it('start a singleFile event for more timeEvent when mMoreTimePrint is true', () => { 188 if (!performanceTimeAndMemPrinter.singleFilePrinter) { 189 performanceTimeAndMemPrinter.singleFilePrinter = new TimeAndMemTimeTracker(); 190 } 191 const eventName = 'test event'; 192 printerTimeAndMemDataConfig.mMoreTimePrint = true; 193 startSingleFileForMoreTimeEvent(eventName); 194 const eventStack = performanceTimeAndMemPrinter.singleFilePrinter?.getEventStack(); 195 const event = eventStack!.find((e) => e.eventName === eventName); 196 expect(event?.eventName).to.be.equal('test event'); 197 }); 198 199 it('start a singleFile event for more timeEvent when mMoreTimePrint is false', () => { 200 const eventName = 'test event'; 201 printerTimeAndMemDataConfig.mMoreTimePrint = false; 202 startSingleFileForMoreTimeEvent(eventName); 203 const eventStack = performanceTimeAndMemPrinter.singleFilePrinter?.getEventStack(); 204 const event = eventStack?.find((e) => e.eventName === eventName); 205 expect(event).to.be.undefined; 206 }); 207 208 it('start a singleFile event for more timeEvent when performanceTimeAndMemPrinter.singleFilePrinter is undefined', () => { 209 const eventName = 'test event'; 210 printerTimeAndMemDataConfig.mMoreTimePrint = true; 211 performanceTimeAndMemPrinter.singleFilePrinter = undefined; 212 expect(() => startSingleFileForMoreTimeEvent(eventName)).to.not.throw; 213 }); 214 }); 215 216 describe('Tester Cases for <endSingleFileForMoreTimeEvent>', () => { 217 it('end a singleFile event for more timeEvent', async () => { 218 if (!performanceTimeAndMemPrinter.singleFilePrinter) { 219 performanceTimeAndMemPrinter.singleFilePrinter = new TimeAndMemTimeTracker(); 220 } 221 const eventName = 'test event'; 222 printerTimeAndMemDataConfig.mMoreTimePrint = true; 223 startSingleFileForMoreTimeEvent(eventName); 224 225 const eventStackBeforeEnd = performanceTimeAndMemPrinter.singleFilePrinter!.getEventStack(); 226 const eventBeforeEnd = eventStackBeforeEnd.find((e) => e.eventName === eventName); 227 228 expect(eventBeforeEnd?.data.start).to.be.greaterThan(0); 229 230 endSingleFileForMoreTimeEvent(eventName); 231 232 const eventStackAfterEnd = performanceTimeAndMemPrinter.singleFilePrinter!.getEventStack(); 233 expect(eventStackAfterEnd.length).to.equal(0); 234 }); 235 236 it('start a singleFile event for more timeEvent when performanceTimeAndMemPrinter.singleFilePrinter is undefined', () => { 237 const eventName = 'test event'; 238 printerTimeAndMemDataConfig.mMoreTimePrint = true; 239 performanceTimeAndMemPrinter.singleFilePrinter = undefined; 240 expect(() => endSingleFileForMoreTimeEvent(eventName)).to.not.throw; 241 }); 242 }); 243 244 describe('Tester Cases for <enableTimeAndMemoryPrint>', () => { 245 const testCacheDir = path.join(__dirname, 'test-cache'); 246 const timePerformanceFilePath = path.join(testCacheDir, 'timePerformanceData.json'); 247 const memoryPerformanceFilePath = path.join(testCacheDir, 'memoryPerformanceData.json'); 248 249 beforeEach(() => { 250 if (!fs.existsSync(testCacheDir)) { 251 fs.mkdirSync(testCacheDir, { recursive: true }); 252 } 253 if (fs.existsSync(timePerformanceFilePath)) { 254 fs.unlinkSync(timePerformanceFilePath); 255 } 256 if (fs.existsSync(memoryPerformanceFilePath)) { 257 fs.unlinkSync(memoryPerformanceFilePath); 258 } 259 260 TimeAndMemTimeTracker.obfuscationCacheDir = testCacheDir; 261 262 if (performanceTimeAndMemPrinter.singleFilePrinter) { 263 performanceTimeAndMemPrinter.singleFilePrinter.timeDataArr = []; 264 performanceTimeAndMemPrinter.singleFilePrinter.memoryDataArr = []; 265 } 266 267 if (performanceTimeAndMemPrinter.filesPrinter) { 268 performanceTimeAndMemPrinter.filesPrinter.timeDataArr = []; 269 performanceTimeAndMemPrinter.filesPrinter.memoryDataArr = []; 270 } 271 }); 272 273 afterEach(() => { 274 if (fs.existsSync(timePerformanceFilePath)) { 275 fs.unlinkSync(timePerformanceFilePath); 276 } 277 if (fs.existsSync(memoryPerformanceFilePath)) { 278 fs.unlinkSync(memoryPerformanceFilePath); 279 } 280 }); 281 282 it('should not print time and memory data when mTimeAndMemPrinter is false', () => { 283 printerTimeAndMemDataConfig.mTimeAndMemPrinter = false; 284 285 enableTimeAndMemoryPrint(); 286 287 expect(fs.existsSync(timePerformanceFilePath)).to.be.false; 288 expect(fs.existsSync(memoryPerformanceFilePath)).to.be.false; 289 }); 290 291 it('should print time and memory data when mTimeAndMemPrinter is true', async () => { 292 printerTimeAndMemDataConfig.mTimeAndMemPrinter = true; 293 294 performanceTimeAndMemPrinter.singleFilePrinter = new TimeAndMemTimeTracker(); 295 performanceTimeAndMemPrinter.singleFilePrinter.timeDataArr.push({ 296 name: 'Test Event', 297 ph: 'X', 298 pid: 1, 299 tid: 1, 300 ts: 1000, 301 dur: 500, 302 }); 303 performanceTimeAndMemPrinter.singleFilePrinter.memoryDataArr.push({ 304 name: 'Test Event', 305 startMemory: '10MB', 306 endMemory: '15MB', 307 }); 308 309 await enableTimeAndMemoryPrint(); 310 await new Promise(resolve => setTimeout(resolve, 100)); 311 312 expect(fs.existsSync(timePerformanceFilePath)).to.be.true; 313 expect(fs.existsSync(memoryPerformanceFilePath)).to.be.true; 314 }); 315 }); 316 317 describe('Tester Cases for <writeTimeAndMemoryPerformanceData>', () => { 318 it('Write file error', () => { 319 const projectConfig = { 320 obfuscationOptions: { 321 obfuscationCacheDir: 'test/', 322 }, 323 }; 324 const data = [ 325 { 326 'name': 'BreakpointConstants.ts', 327 'startMemory': '318.945MB', 328 'endMemory': '320.114MB', 329 }, 330 ]; 331 const fileName = ''; 332 getObfuscationCacheDir(projectConfig); 333 expect(writeTimeAndMemoryPerformanceData(data, fileName)).to.be.throw; 334 }); 335 }); 336 337 describe('Tester Cases for <getObfuscationCacheDir>', () => { 338 it('get obfuscation and cache dir when cacheDir is exited', () => { 339 const projectConfig = { 340 obfuscationOptions: { 341 obfuscationCacheDir: 'test/', 342 }, 343 }; 344 getObfuscationCacheDir(projectConfig); 345 expect(TimeAndMemTimeTracker.obfuscationCacheDir).to.equal('test/'); 346 }); 347 348 it('get obfuscation and cache dir when obfuscationOptions is undefined', () => { 349 const projectConfig = { 350 obfuscationOptions: undefined, 351 }; 352 getObfuscationCacheDir(projectConfig); 353 expect(TimeAndMemTimeTracker.obfuscationCacheDir).to.be.undefined; 354 }); 355 }); 356 357 describe('Tester Cases for <getTimePerformanceData>', () => { 358 it('get time performance data', () => { 359 performanceTimeAndMemPrinter.filesPrinter = undefined; 360 performanceTimeAndMemPrinter.singleFilePrinter = undefined; 361 const array = getTimePerformanceData(); 362 expect(array.length === 0).to.be.true; 363 }); 364 }); 365 366 describe('Tester Cases for <getMemoryPerformanceData>', () => { 367 it('get memory performance data', () => { 368 performanceTimeAndMemPrinter.filesPrinter = undefined; 369 performanceTimeAndMemPrinter.singleFilePrinter = undefined; 370 const array = getMemoryPerformanceData(); 371 expect(array.length === 0).to.be.true; 372 }); 373 }); 374}); 375