• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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