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 { Core } from '../../core'; 17import { ClassFilter, NotClassFilter, SuiteAndItNameFilter, TestTypesFilter, NestFilter } from './Filter'; 18import { TAG, TESTTYPE, LEVEL, SIZE, KEYSET } from '../../Constant'; 19import { ConfigIf, ServiceAttrIF, FilterParamIF } from '../../interface'; 20import { SuiteService } from '../service/SuiteService'; 21const STRESS_RULE = new RegExp('^[1-9]\\d*$'); 22 23class ConfigService { 24 public id: string; 25 public supportAsync: boolean; 26 public random: boolean; 27 public filterValid: Array<string>; 28 public filter: int; 29 public flag: boolean; 30 public suite: string; 31 public itName: string; 32 public testType: string; 33 public level: string; 34 public size: string; 35 public className: string; 36 public notClass: string; 37 public timeout: string; 38 public breakOnError: boolean | string; 39 public stress: string; 40 public skipMessage: boolean; 41 public runSkipped: string; 42 public filterXdescribe: Array<string>; 43 public dryRun: string; 44 public coverage: string; 45 public coreContext: Core; 46 private filterParam: FilterParamIF | null; 47 constructor(attr: ServiceAttrIF) { 48 this.id = attr.id; 49 this.supportAsync = true; // 默认异步处理测试用例 50 this.random = false; 51 this.filterValid = new Array<string>(); 52 this.filter = 0; 53 this.flag = false; 54 this.suite = ''; 55 this.itName = ''; 56 this.testType = ''; 57 this.level = ''; 58 this.size = ''; 59 this.className = ''; 60 this.notClass = ''; 61 this.timeout = ''; 62 63 this.breakOnError = false; 64 65 this.stress = ''; 66 this.dryRun = ''; 67 this.coverage = ''; 68 this.skipMessage = false; 69 this.runSkipped = ''; 70 this.filterXdescribe = new Array<string>(); 71 this.filterParam = null; 72 this.coreContext = new Core(); 73 } 74 75 init(coreContext: Core) { 76 this.coreContext = coreContext; 77 } 78 79 isNormalInteger(str: string) { 80 const n = Math.floor(Number(str)); 81 return n !== Infinity && String(n) === String(str) && n >= 0; 82 } 83 getStress(): number { 84 if (this.stress === undefined || this.stress === '' || this.stress === null) { 85 return 1; 86 } 87 if (!STRESS_RULE.test(this.stress)) { 88 return 1; 89 } else { 90 return Number.parseInt(this.stress); 91 } 92 } 93 94 basicParamValidCheck(params: ConfigIf) { 95 const size = params.size; 96 if (size) { 97 const sizeArray = new Array<string>('small', 'medium', 'large'); 98 if (sizeArray.indexOf(size) === -1) { 99 this.filterValid.push('size:' + size); 100 } 101 } 102 const level = params.level; 103 if (level) { 104 const levelArray = new Array<string>('0', '1', '2', '3', '4'); 105 if (levelArray.indexOf(level) === -1) { 106 this.filterValid.push('level:' + level); 107 } 108 } 109 const testType = params.testType; 110 if (testType) { 111 const testTypeArray = new Array<string>( 112 'function', 113 'performance', 114 'power', 115 'reliability', 116 'security', 117 'global', 118 'compatibility', 119 'user', 120 'standard', 121 'safety', 122 'resilience' 123 ); 124 if (testTypeArray.indexOf(testType) === -1) { 125 this.filterValid.push('testType:' + testType); 126 } 127 } 128 } 129 130 filterParamValidCheck(params: ConfigIf) { 131 let timeout = params.timeout; 132 if (timeout) { 133 if (!this.isNormalInteger(timeout)) { 134 this.filterValid.push('timeout:' + timeout); 135 } 136 } 137 138 if (params.dryRun) { 139 if (params.dryRun !== 'true' && params.dryRun !== 'false') { 140 this.filterValid.push(`dryRun:${params.dryRun}`); 141 } 142 } 143 if (params.random) { 144 if (params.random !== 'true' && params.random !== 'false') { 145 this.filterValid.push(`random:${params.random}`); 146 } 147 } 148 if (params.breakOnError) { 149 if (params.breakOnError !== 'true' && params.breakOnError !== 'false') { 150 this.filterValid.push(`breakOnError:${params.breakOnError}`); 151 } 152 } 153 if (params.coverage) { 154 if (params.coverage !== 'true' && params.coverage !== 'false') { 155 this.filterValid.push(`coverage:${params.coverage}`); 156 } 157 } 158 if (params.skipMessage) { 159 if (params.skipMessage !== 'true' && params.skipMessage !== 'false') { 160 this.filterValid.push(`skipMessage:${params.skipMessage}`); 161 } 162 } 163 if (params.stress) { 164 if (!STRESS_RULE.test(params.stress as string)) { 165 this.filterValid.push('stress:' + params.stress); 166 } 167 } 168 169 const nameRule = new RegExp('^[A-Za-z]{1}[\\w#,.]*$'); 170 if (params.className) { 171 const classList = (params.className as string).split(','); 172 const classArray = new Array<string>(); 173 for (let value of classList) { 174 classArray.push(value); 175 } 176 classArray.forEach((item: string) => { 177 if (!item.match(nameRule)) { 178 this.filterValid.push(`className:${params.className}`); 179 } 180 }); 181 } 182 } 183 184 setConfig(params: ConfigIf) { 185 this.basicParamValidCheck(params); 186 this.filterParamValidCheck(params); 187 try { 188 if (params.className) { 189 this.className = params.className as string; 190 } 191 if (params.notClass) { 192 this.notClass = params.notClass as string; 193 } 194 if (params.flag !== undefined) { 195 this.flag = params.flag as boolean; 196 } 197 if (params.suite) { 198 this.suite = params.suite as string; 199 } 200 if (params.itName) { 201 this.itName = params.itName as string; 202 } 203 if (params.filter !== undefined) { 204 this.filter = params.filter as int; 205 } 206 if (params.testType) { 207 this.testType = params.testType as string; 208 } 209 if (params.level) { 210 this.level = params.level as string; 211 } 212 if (params.size) { 213 this.size = params.size as string; 214 } 215 if (params.timeout) { 216 this.timeout = params.timeout as string; 217 } 218 if (params.dryRun) { 219 this.dryRun = params.dryRun as string; 220 } 221 if (params.breakOnError) { 222 this.breakOnError = params.breakOnError as string; 223 } 224 if (params.stress) { 225 this.stress = params.stress as string; 226 } 227 if (params.coverage) { 228 this.coverage = params.coverage as string; 229 } 230 if (params.skipMessage) { 231 this.skipMessage = Boolean(params.skipMessage); 232 } 233 if (params.runSkipped) { 234 this.runSkipped = params.runSkipped as string; 235 } 236 this.random = params.random === 'true' ? true : false; 237 this.filterParam = { 238 testType: TESTTYPE, 239 level: LEVEL, 240 size: SIZE, 241 } as FilterParamIF; 242 this.parseParams(); 243 } catch (err: Error) { 244 console.info(`${TAG}setConfig error: ${err.message}`); 245 } 246 } 247 248 parseParams() { 249 if (this.filter !== 0) { 250 return; 251 } 252 let testTypeFilter = 0; 253 let sizeFilter = 0; 254 let levelFilter = 0; 255 if (this.testType !== null) { 256 const testTypeList = this.testType.split(','); 257 const testTypeArr = new Array<string>(); 258 for (const testTypeV of testTypeList) { 259 if (testTypeV !== undefined) { 260 testTypeArr.push(testTypeV); 261 } 262 } 263 const testTypeMapList = testTypeArr.map((item: string) => { 264 if (this.filterParam) { 265 const p = this.filterParam as FilterParamIF; 266 if (p.testType) { 267 const type = p.testType as Map<string, int>; 268 const res = type.get(item); 269 if (res) { 270 return res; 271 } else { 272 return 0; 273 } 274 } 275 } 276 return 0; 277 }); 278 const testTypeArray = new Array<int>(); 279 for (const testTypeV of testTypeMapList) { 280 if (testTypeV !== undefined) { 281 testTypeArray.push(testTypeV); 282 } 283 } 284 testTypeFilter = testTypeArray.reduce((pre: int, cur: int) => pre | cur, 0); 285 } 286 if (this.level !== null) { 287 const levelList = this.level.split(','); 288 const levelArr = new Array<string>(); 289 for (const levelV of levelList) { 290 levelArr.push(levelV); 291 } 292 const levelMapList = levelArr.map((item: string) => { 293 if (item === '') { 294 return 0; 295 } 296 if (this.filterParam) { 297 const p = this.filterParam as FilterParamIF; 298 if (p.level) { 299 const level = p.level as int[]; 300 const res = level[Number(item) as int]; 301 if (res) { 302 return res; 303 } else { 304 return 0; 305 } 306 } 307 } 308 return 0; 309 }); 310 const levelArray = new Array<int>(); 311 for (const levelV of levelMapList) { 312 levelArray.push(levelV); 313 } 314 levelFilter = levelArray.reduce((pre: int, cur: int) => pre | cur, 0); 315 } 316 if (this.size !== null) { 317 const sizeList = this.size.split(','); 318 const sizeArr = new Array<string>(); 319 for (const sizeV of sizeList) { 320 sizeArr.push(sizeV); 321 } 322 const sizeMapList = sizeArr.map((item: string): int => { 323 if (this.filterParam) { 324 const p = this.filterParam as FilterParamIF; 325 if (p.size) { 326 const size = p.size as Map<string, int>; 327 const res = size.get(item); 328 if (res) { 329 return res; 330 } else { 331 return 0; 332 } 333 } 334 } 335 return 0; 336 }); 337 const sizeArray = new Array<int>(); 338 for (const sizeV of sizeMapList) { 339 if (sizeV !== undefined) { 340 sizeArray.push(sizeV); 341 } 342 } 343 sizeFilter = sizeArray.reduce((pre: int, cur: int) => pre | cur, 0); 344 } 345 this.filter = testTypeFilter | sizeFilter | levelFilter; 346 console.info(`${TAG}filter params:${this.filter}`); 347 } 348 349 isCurrentSuite(description: string) { 350 if (this.suite !== undefined && this.suite !== '' && this.suite !== null) { 351 const suiteList = this.suite.split(','); 352 const suiteArray = new Array<string>(); 353 for (let suite of suiteList) { 354 suiteArray.push(suite); 355 } 356 return suiteArray.indexOf(description) !== -1; 357 } 358 return false; 359 } 360 361 filterSuite(currentSuiteName: string): boolean { 362 const filterArray1 = new Array<SuiteAndItNameFilter>(); 363 if (this.suite !== undefined && this.suite !== '' && this.suite !== null) { 364 filterArray1.push(new SuiteAndItNameFilter(currentSuiteName, '', this.suite)); 365 } 366 const mapArray1 = filterArray1.map((item: SuiteAndItNameFilter) => item.filterSuite()); 367 const reduce1 = mapArray1.reduce((pre: boolean, cur: boolean) => pre || cur, false); 368 369 const filterArray2 = new Array<ClassFilter>(); 370 if (this.className !== undefined && this.className !== '' && this.className !== null) { 371 filterArray2.push(new ClassFilter(currentSuiteName, '', this.className)); 372 } 373 const mapArray2 = filterArray2.map((item: ClassFilter) => item.filterSuite()); 374 const reduce2 = mapArray2.reduce((pre: boolean, cur: boolean) => pre || cur, false); 375 376 const filterArray3 = new Array<NotClassFilter>(); 377 if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) { 378 filterArray3.push(new NotClassFilter(currentSuiteName, '', this.notClass)); 379 } 380 const mapArray3 = filterArray3.map((item: NotClassFilter) => item.filterSuite()); 381 const reduce3 = mapArray3.reduce((pre: boolean, cur: boolean) => pre || cur, false); 382 return reduce1 || reduce2 || reduce3; 383 } 384 385 filterDesc(currentSuiteName: string, desc: string, fi: int): boolean { 386 const suiteAndItNameFilterArray = new Array<SuiteAndItNameFilter>(); 387 const classFilterArray = new Array<ClassFilter>(); 388 const notClassFilterArray = new Array<NotClassFilter>(); 389 const testTypesFilterArray = new Array<TestTypesFilter>(); 390 if (this.itName !== undefined && this.itName !== '' && this.itName !== null) { 391 suiteAndItNameFilterArray.push(new SuiteAndItNameFilter(currentSuiteName, desc, this.itName)); 392 } 393 if (this.className !== undefined && this.className !== '' && this.className !== null) { 394 classFilterArray.push(new ClassFilter(currentSuiteName, desc, this.className)); 395 } 396 if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) { 397 notClassFilterArray.push(new NotClassFilter(currentSuiteName, desc, this.notClass)); 398 } 399 if (typeof this.filter !== 'undefined' && this.filter !== 0 && fi !== 0) { 400 testTypesFilterArray.push(new TestTypesFilter('', '', fi, this.filter)); 401 } 402 const suiteAndItNameFilterResult = suiteAndItNameFilterArray 403 .map((item: SuiteAndItNameFilter) => item.filterIt()) 404 .reduce((pre: boolean, cur: boolean) => pre || cur, false); 405 const classFilterResult = classFilterArray 406 .map((item: ClassFilter) => item.filterIt()) 407 .reduce((pre: boolean, cur: boolean) => pre || cur, false); 408 const notClassFilterResult = notClassFilterArray 409 .map((item: NotClassFilter) => item.filterIt()) 410 .reduce((pre: boolean, cur: boolean) => pre || cur, false); 411 const testTypesFilterResult = testTypesFilterArray 412 .map((item: TestTypesFilter) => item.filterIt()) 413 .reduce((pre: boolean, cur: boolean) => pre || cur, false); 414 return suiteAndItNameFilterResult || classFilterResult || notClassFilterResult || testTypesFilterResult; 415 } 416 417 filterWithNest(desc: string, filter: int): boolean { 418 let filterArray = new Array<TestTypesFilter>(); 419 const nestFilter = new NestFilter(); 420 const core = this.coreContext; 421 if (core !== null) { 422 const coreContext = core as Core; 423 const suite = coreContext.getDefaultService('suite'); 424 if (suite !== null) { 425 const defaultService = suite as SuiteService; 426 const targetSuiteArray = defaultService.targetSuiteArray; 427 const targetSpecArray = defaultService.targetSpecArray; 428 const suiteStack = defaultService.suitesStack; 429 let isFilter = nestFilter.filterNestName(targetSuiteArray, targetSpecArray, suiteStack, desc); 430 const isFullRun = defaultService.fullRun; 431 if (this.filter && filter) { 432 filterArray.push(new TestTypesFilter('', '', filter, this.filter)); 433 return filterArray 434 .map((item: TestTypesFilter) => item.filterIt()) 435 .reduce((pre: boolean, cur: boolean) => pre || cur, false); 436 } 437 if (isFilter && !isFullRun) { 438 return true; 439 } 440 return nestFilter.filterNotClass(this.notClass, suiteStack, desc); 441 } 442 } 443 444 return false; 445 } 446 447 isRandom() { 448 return this.random || false; 449 } 450 451 isBreakOnError(): boolean { 452 return this.breakOnError !== 'true' ? false : true; 453 } 454 455 setSupportAsync(value: boolean) { 456 this.supportAsync = value; 457 } 458 459 isSupportAsync() { 460 return this.supportAsync; 461 } 462 463 translateParams(parameters: Record<string, string>): ConfigIf { 464 const keySet = new Set<string>(KEYSET); 465 const targetParams: ConfigIf = {}; 466 for (const key of parameters.keys()) { 467 if (keySet.has(key)) { 468 const newKey = key.replace('-s ', ''); 469 if (newKey === 'class') { 470 targetParams.className = parameters[key]; 471 } else if (newKey === 'notClass') { 472 targetParams.notClass = parameters[key]; 473 } else if (newKey === 'suite') { 474 targetParams.suite = parameters[key]; 475 } else if (newKey === 'itName') { 476 targetParams.itName = parameters[key]; 477 } else if (newKey === 'level') { 478 targetParams.level = parameters[key]; 479 } else if (newKey === 'testType') { 480 targetParams.testType = parameters[key]; 481 } else if (newKey === 'size') { 482 targetParams.size = parameters[key]; 483 } else if (newKey === 'timeout') { 484 targetParams.timeout = parameters[key]; 485 } else if (newKey === 'dryRun') { 486 targetParams.dryRun = parameters[key]; 487 } else if (newKey === 'random') { 488 targetParams.random = parameters[key]; 489 } else if (newKey === 'breakOnError') { 490 targetParams.breakOnError = parameters[key]; 491 } else if (newKey === 'stress') { 492 targetParams.stress = parameters[key]; 493 } else if (newKey === 'coverage') { 494 targetParams.coverage = parameters[key]; 495 } else if (newKey === 'skipMessage') { 496 targetParams.skipMessage = parameters[key]; 497 } else if (newKey === 'runSkipped') { 498 targetParams.runSkipped = parameters[key]; 499 } 500 } 501 } 502 return targetParams; 503 } 504 translateParamsToString(parameters: Record<string, string>) { 505 const keySet = new Set<string>(KEYSET); 506 let targetParams = ''; 507 for (const key of Object.keys(parameters)) { 508 if (keySet.has(key)) { 509 targetParams += ' ' + key + ' ' + parameters[key]; 510 } 511 } 512 return targetParams.trim(); 513 } 514 515 execute() {} 516 517 checkIfSuiteInSkipRun(desc: string): boolean { 518 const list = this.runSkipped.split(','); 519 const arr = new Array<string>(); 520 for (let v of list) { 521 arr.push(v); 522 } 523 return arr.some((item: string) => { 524 return ( 525 item === desc || 526 item.startsWith(desc + '.') || 527 item.startsWith(desc + '#') || 528 desc.startsWith(item + '.') || 529 this.runSkipped === 'skipped' 530 ); 531 }); 532 } 533 534 checkIfSpecInSkipRun(desc: string): boolean { 535 const list = this.runSkipped.split(','); 536 const arr = new Array<string>(); 537 for (let v of list) { 538 arr.push(v); 539 } 540 return arr.some((item: string) => { 541 if (item.includes('#')) { 542 return item === desc; 543 } else { 544 return desc.startsWith(item + '.') || desc.startsWith(item + '#') || this.runSkipped === 'skipped'; 545 } 546 }); 547 } 548} 549 550export { ConfigService }; 551