From 3869f7cbea6f2868da46cb63aadb4826531d95e1 Mon Sep 17 00:00:00 2001 From: stanislavh Date: Fri, 14 Jul 2023 11:02:57 +0200 Subject: [PATCH] SONAR-18424 Move mocked data out from RuleServiceMock --- .../js/api/mocks/CodingRulesServiceMock.ts | 228 ++---------------- .../src/main/js/api/mocks/data/ids.ts | 37 +++ .../main/js/api/mocks/data/qualityProfiles.ts | 41 ++++ .../src/main/js/api/mocks/data/rules.ts | 189 ++++++++++++++- 4 files changed, 279 insertions(+), 216 deletions(-) create mode 100644 server/sonar-web/src/main/js/api/mocks/data/qualityProfiles.ts diff --git a/server/sonar-web/src/main/js/api/mocks/CodingRulesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/CodingRulesServiceMock.ts index ba49e9f5cfc..796f85fba48 100644 --- a/server/sonar-web/src/main/js/api/mocks/CodingRulesServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/CodingRulesServiceMock.ts @@ -23,7 +23,6 @@ import { getStandards } from '../../helpers/security-standard'; import { mockCurrentUser, mockPaging, - mockQualityProfile, mockRuleActivation, mockRuleDetails, mockRuleRepository, @@ -31,7 +30,7 @@ import { import { RuleRepository, SearchRulesResponse } from '../../types/coding-rules'; import { RawIssuesResponse } from '../../types/issues'; import { SearchRulesQuery } from '../../types/rules'; -import { SecurityStandard, Standards } from '../../types/security'; +import { SecurityStandard } from '../../types/security'; import { Dict, Rule, RuleActivation, RuleDetails, RulesUpdateRequest } from '../../types/types'; import { NoticeType } from '../../types/users'; import { getFacet } from '../issues'; @@ -57,6 +56,9 @@ import { updateRule, } from '../rules'; import { dismissNotice, getCurrentUser } from '../users'; +import { STANDARDS_TO_RULES } from './data/ids'; +import { mockQualityProfilesList } from './data/qualityProfiles'; +import { mockRuleDetailsList, mockRulesActivationsInQP } from './data/rules'; type FacetFilter = Pick< SearchRulesQuery, @@ -87,8 +89,6 @@ const FACET_RULE_MAP: { [key: string]: keyof Rule } = { export const RULE_TAGS_MOCK = ['awesome', 'cute', 'nice']; export default class CodingRulesServiceMock { - defaultRules: RuleDetails[] = []; - defaultRulesActivations: Dict = {}; rulesActivations: Dict = {}; rules: RuleDetails[] = []; qualityProfile: Profile[] = []; @@ -96,211 +96,15 @@ export default class CodingRulesServiceMock { isAdmin = false; applyWithWarning = false; dismissedNoticesEP = false; - standardsToRules: Partial<{ [category in keyof Standards]: { [standard: string]: string[] } }> = - {}; constructor() { this.repositories = [ mockRuleRepository({ key: 'repo1', name: 'Repository 1' }), mockRuleRepository({ key: 'repo2', name: 'Repository 2' }), ]; - this.qualityProfile = [ - mockQualityProfile({ - key: 'p1', - name: 'QP Foo', - language: 'java', - languageName: 'Java', - actions: { edit: true }, - }), - mockQualityProfile({ key: 'p2', name: 'QP Bar', language: 'js' }), - mockQualityProfile({ key: 'p3', name: 'QP FooBar', language: 'java', languageName: 'Java' }), - mockQualityProfile({ - key: 'p4', - name: 'QP FooBarBaz', - language: 'java', - languageName: 'Java', - }), - ]; - - const resourceContent = 'Some link Awsome Reading'; - const introTitle = 'Introduction to this rule'; - const rootCauseContent = 'Root cause'; - const howToFixContent = 'This is how to fix'; - - this.defaultRules = [ - mockRuleDetails({ - key: 'rule1', - repo: 'repo1', - type: 'BUG', - lang: 'java', - langName: 'Java', - name: 'Awsome java rule', - tags: ['awesome'], - params: [ - { key: '1', type: 'TEXT', htmlDesc: 'html description for key 1' }, - { key: '2', type: 'NUMBER', defaultValue: 'default value for key 2' }, - ], - }), - mockRuleDetails({ - key: 'rule2', - repo: 'repo1', - name: 'Hot hotspot', - tags: ['awesome'], - type: 'SECURITY_HOTSPOT', - lang: 'js', - descriptionSections: [ - { key: RuleDescriptionSections.INTRODUCTION, content: introTitle }, - { key: RuleDescriptionSections.ROOT_CAUSE, content: rootCauseContent }, - { key: RuleDescriptionSections.HOW_TO_FIX, content: howToFixContent }, - { key: RuleDescriptionSections.ASSESS_THE_PROBLEM, content: 'Assess' }, - { - key: RuleDescriptionSections.RESOURCES, - content: resourceContent, - }, - ], - langName: 'JavaScript', - }), - mockRuleDetails({ - key: 'rule3', - repo: 'repo2', - name: 'Unknown rule', - lang: 'js', - langName: 'JavaScript', - }), - mockRuleDetails({ - key: 'rule4', - type: 'BUG', - lang: 'c', - langName: 'C', - name: 'Awsome C rule', - }), - mockRuleDetails({ - key: 'rule5', - type: 'VULNERABILITY', - lang: 'py', - langName: 'Python', - name: 'Awsome Python rule', - descriptionSections: [ - { key: RuleDescriptionSections.INTRODUCTION, content: introTitle }, - { key: RuleDescriptionSections.HOW_TO_FIX, content: rootCauseContent }, - { - key: RuleDescriptionSections.RESOURCES, - content: resourceContent, - }, - ], - }), - mockRuleDetails({ - key: 'rule6', - type: 'BUG', - lang: 'py', - langName: 'Python', - name: 'Bad Python rule', - isExternal: true, - descriptionSections: undefined, - }), - mockRuleDetails({ - key: 'rule7', - type: 'VULNERABILITY', - severity: 'MINOR', - lang: 'py', - langName: 'Python', - name: 'Python rule with context', - descriptionSections: [ - { - key: RuleDescriptionSections.INTRODUCTION, - content: 'Introduction to this rule with context', - }, - { - key: RuleDescriptionSections.HOW_TO_FIX, - content: 'This is how to fix for spring', - context: { key: 'spring', displayName: 'Spring' }, - }, - { - key: RuleDescriptionSections.HOW_TO_FIX, - content: 'This is how to fix for spring boot', - context: { key: 'spring_boot', displayName: 'Spring boot' }, - }, - { - key: RuleDescriptionSections.RESOURCES, - content: resourceContent, - }, - ], - }), - mockRuleDetails({ - key: 'rule8', - type: 'BUG', - severity: 'MINOR', - lang: 'py', - langName: 'Python', - tags: ['awesome'], - name: 'Template rule', - params: [ - { key: '1', type: 'TEXT', htmlDesc: 'html description for key 1' }, - { key: '2', type: 'NUMBER', defaultValue: 'default value for key 2' }, - ], - isTemplate: true, - }), - mockRuleDetails({ - key: 'rule9', - type: 'BUG', - severity: 'MINOR', - lang: 'py', - langName: 'Python', - tags: ['awesome', 'cute'], - name: 'Custom Rule based on rule8', - params: [ - { key: '1', type: 'TEXT', htmlDesc: 'html description for key 1' }, - { key: '2', type: 'NUMBER', defaultValue: 'default value for key 2' }, - ], - templateKey: 'rule8', - }), - mockRuleDetails({ - createdAt: '2022-12-16T17:26:54+0100', - key: 'rule10', - type: 'VULNERABILITY', - severity: 'MINOR', - lang: 'py', - langName: 'Python', - tags: ['awesome'], - name: 'Awesome Python rule with education principles', - descriptionSections: [ - { key: RuleDescriptionSections.INTRODUCTION, content: introTitle }, - { key: RuleDescriptionSections.HOW_TO_FIX, content: rootCauseContent }, - { - key: RuleDescriptionSections.RESOURCES, - content: resourceContent, - }, - ], - educationPrinciples: ['defense_in_depth', 'never_trust_user_input'], - }), - mockRuleDetails({ - key: 'rule11', - type: 'BUG', - lang: 'java', - langName: 'Java', - name: 'Common java rule', - }), - ]; - - this.defaultRulesActivations = { - [this.defaultRules[0].key]: [mockRuleActivation({ qProfile: 'p1' })], - }; - - this.standardsToRules = { - [SecurityStandard.SONARSOURCE]: { - 'buffer-overflow': ['rule1', 'rule2', 'rule3', 'rule4', 'rule5', 'rule6'], - }, - [SecurityStandard.OWASP_TOP10_2021]: { - a2: ['rule1', 'rule2', 'rule3', 'rule4', 'rule5'], - }, - [SecurityStandard.OWASP_TOP10]: { - a3: ['rule1', 'rule2', 'rule3', 'rule4'], - }, - [SecurityStandard.CWE]: { - '102': ['rule1', 'rule2', 'rule3'], - '297': ['rule1', 'rule4'], - }, - }; + this.qualityProfile = mockQualityProfilesList(); + this.rules = mockRuleDetailsList(); + this.rulesActivations = mockRulesActivationsInQP(); jest.mocked(updateRule).mockImplementation(this.handleUpdateRule); jest.mocked(createRule).mockImplementation(this.handleCreateRule); @@ -318,8 +122,6 @@ export default class CodingRulesServiceMock { jest.mocked(getRuleTags).mockImplementation(this.handleGetRuleTags); jest.mocked(getCurrentUser).mockImplementation(this.handleGetCurrentUser); jest.mocked(dismissNotice).mockImplementation(this.handleDismissNotification); - this.rules = cloneDeep(this.defaultRules); - this.rulesActivations = cloneDeep(this.defaultRulesActivations); } getRulesWithoutDetails(rules: RuleDetails[]) { @@ -366,7 +168,7 @@ export default class CodingRulesServiceMock { if (severities) { filteredRules = filteredRules.filter((r) => r.severity && severities.includes(r.severity)); } - if (qprofile && activation !== undefined) { + if (qprofile) { const qProfileLang = this.qualityProfile.find((p) => p.key === qprofile)?.language; filteredRules = filteredRules .filter((r) => r.lang === qProfileLang) @@ -375,8 +177,6 @@ export default class CodingRulesServiceMock { const ruleHasQueriedProfile = qProfilesInRule.includes(qprofile); return activation === 'true' ? ruleHasQueriedProfile : !ruleHasQueriedProfile; }); - - console.log(filteredRules); } if (available_since) { filteredRules = filteredRules.filter( @@ -391,20 +191,20 @@ export default class CodingRulesServiceMock { } if (sonarsourceSecurity) { const matchingRules = - this.standardsToRules[SecurityStandard.SONARSOURCE]?.[sonarsourceSecurity] ?? []; + STANDARDS_TO_RULES[SecurityStandard.SONARSOURCE]?.[sonarsourceSecurity] ?? []; filteredRules = filteredRules.filter((r) => matchingRules.includes(r.key)); } if (owasp2021Top10) { const matchingRules = - this.standardsToRules[SecurityStandard.OWASP_TOP10_2021]?.[owasp2021Top10] ?? []; + STANDARDS_TO_RULES[SecurityStandard.OWASP_TOP10_2021]?.[owasp2021Top10] ?? []; filteredRules = filteredRules.filter((r) => matchingRules.includes(r.key)); } if (owaspTop10) { - const matchingRules = this.standardsToRules[SecurityStandard.OWASP_TOP10]?.[owaspTop10] ?? []; + const matchingRules = STANDARDS_TO_RULES[SecurityStandard.OWASP_TOP10]?.[owaspTop10] ?? []; filteredRules = filteredRules.filter((r) => matchingRules.includes(r.key)); } if (cwe) { - const matchingRules = this.standardsToRules[SecurityStandard.CWE]?.[cwe] ?? []; + const matchingRules = STANDARDS_TO_RULES[SecurityStandard.CWE]?.[cwe] ?? []; filteredRules = filteredRules.filter((r) => matchingRules.includes(r.key)); } if (q && q.length > 2) { @@ -428,8 +228,8 @@ export default class CodingRulesServiceMock { this.isAdmin = false; this.applyWithWarning = false; this.dismissedNoticesEP = false; - this.rules = cloneDeep(this.defaultRules); - this.rulesActivations = cloneDeep(this.defaultRulesActivations); + this.rules = mockRuleDetailsList(); + this.rulesActivations = mockRulesActivationsInQP(); } allRulesCount() { diff --git a/server/sonar-web/src/main/js/api/mocks/data/ids.ts b/server/sonar-web/src/main/js/api/mocks/data/ids.ts index 2db8be77c11..db4aa491ecb 100644 --- a/server/sonar-web/src/main/js/api/mocks/data/ids.ts +++ b/server/sonar-web/src/main/js/api/mocks/data/ids.ts @@ -18,6 +18,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { SecurityStandard, Standards } from '../../../types/security'; + // Component tree. export const PARENT_COMPONENT_KEY = 'foo'; //// Root folder. @@ -37,6 +39,23 @@ export const SIMPLE_RULE = 'simpleRuleId'; export const ADVANCED_RULE = 'advancedRuleId'; export const S6069_RULE = 'cpp:S6069'; export const S131_RULE = 'tsql:S131'; +export const RULE_1 = 'rule1'; +export const RULE_2 = 'rule2'; +export const RULE_3 = 'rule3'; +export const RULE_4 = 'rule4'; +export const RULE_5 = 'rule5'; +export const RULE_6 = 'rule6'; +export const RULE_7 = 'rule7'; +export const RULE_8 = 'rule8'; +export const RULE_9 = 'rule9'; +export const RULE_10 = 'rule10'; +export const RULE_11 = 'rule11'; + +// Quality Profiles. +export const QP_1 = 'p1'; +export const QP_2 = 'p2'; +export const QP_3 = 'p3'; +export const QP_4 = 'p4'; // Issues. export const ISSUE_0 = 'issue0'; @@ -77,3 +96,21 @@ export const ISSUE_TO_FILES = { [ISSUE_1102]: [`${FOLDER1_KEY}/${FILE8_KEY}`], [ISSUE_1103]: [`${FOLDER1_KEY}/${FILE8_KEY}`], }; + +export const STANDARDS_TO_RULES: Partial<{ + [category in keyof Standards]: { [standard: string]: string[] }; +}> = { + [SecurityStandard.SONARSOURCE]: { + 'buffer-overflow': [RULE_1, RULE_2, RULE_3, RULE_4, RULE_5, RULE_6], + }, + [SecurityStandard.OWASP_TOP10_2021]: { + a2: [RULE_1, RULE_2, RULE_3, RULE_4, RULE_5], + }, + [SecurityStandard.OWASP_TOP10]: { + a3: [RULE_1, RULE_2, RULE_3, RULE_4], + }, + [SecurityStandard.CWE]: { + '102': [RULE_1, RULE_2, RULE_3], + '297': [RULE_1, RULE_4], + }, +}; diff --git a/server/sonar-web/src/main/js/api/mocks/data/qualityProfiles.ts b/server/sonar-web/src/main/js/api/mocks/data/qualityProfiles.ts new file mode 100644 index 00000000000..de989317103 --- /dev/null +++ b/server/sonar-web/src/main/js/api/mocks/data/qualityProfiles.ts @@ -0,0 +1,41 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { mockQualityProfile } from '../../../helpers/testMocks'; +import { QP_1, QP_2, QP_3, QP_4 } from './ids'; + +export function mockQualityProfilesList() { + return [ + mockQualityProfile({ + key: QP_1, + name: 'QP Foo', + language: 'java', + languageName: 'Java', + actions: { edit: true }, + }), + mockQualityProfile({ key: QP_2, name: 'QP Bar', language: 'js' }), + mockQualityProfile({ key: QP_3, name: 'QP FooBar', language: 'java', languageName: 'Java' }), + mockQualityProfile({ + key: QP_4, + name: 'QP FooBarBaz', + language: 'java', + languageName: 'Java', + }), + ]; +} diff --git a/server/sonar-web/src/main/js/api/mocks/data/rules.ts b/server/sonar-web/src/main/js/api/mocks/data/rules.ts index de3de9bf095..785966acdb7 100644 --- a/server/sonar-web/src/main/js/api/mocks/data/rules.ts +++ b/server/sonar-web/src/main/js/api/mocks/data/rules.ts @@ -18,8 +18,25 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { mockRule } from '../../../helpers/testMocks'; -import { ADVANCED_RULE, S131_RULE, S6069_RULE, SIMPLE_RULE } from './ids'; +import { RuleDescriptionSections } from '../../../apps/coding-rules/rule'; +import { mockRule, mockRuleActivation, mockRuleDetails } from '../../../helpers/testMocks'; +import { + ADVANCED_RULE, + RULE_1, + RULE_10, + RULE_11, + RULE_2, + RULE_3, + RULE_4, + RULE_5, + RULE_6, + RULE_7, + RULE_8, + RULE_9, + S131_RULE, + S6069_RULE, + SIMPLE_RULE, +} from './ids'; export function mockRuleList() { return [ @@ -52,3 +69,171 @@ export function mockRuleList() { }), ]; } + +export const resourceContent = 'Some link Awsome Reading'; +export const introTitle = 'Introduction to this rule'; +export const rootCauseContent = 'Root cause'; +export const howToFixContent = 'This is how to fix'; + +export function mockRuleDetailsList() { + return [ + mockRuleDetails({ + key: RULE_1, + repo: 'repo1', + type: 'BUG', + lang: 'java', + langName: 'Java', + name: 'Awsome java rule', + tags: ['awesome'], + params: [ + { key: '1', type: 'TEXT', htmlDesc: 'html description for key 1' }, + { key: '2', type: 'NUMBER', defaultValue: 'default value for key 2' }, + ], + }), + mockRuleDetails({ + key: RULE_2, + repo: 'repo1', + name: 'Hot hotspot', + tags: ['awesome'], + type: 'SECURITY_HOTSPOT', + lang: 'js', + descriptionSections: [ + { key: RuleDescriptionSections.INTRODUCTION, content: introTitle }, + { key: RuleDescriptionSections.ROOT_CAUSE, content: rootCauseContent }, + { key: RuleDescriptionSections.HOW_TO_FIX, content: howToFixContent }, + { key: RuleDescriptionSections.ASSESS_THE_PROBLEM, content: 'Assess' }, + { + key: RuleDescriptionSections.RESOURCES, + content: resourceContent, + }, + ], + langName: 'JavaScript', + }), + mockRuleDetails({ + key: RULE_3, + repo: 'repo2', + name: 'Unknown rule', + lang: 'js', + langName: 'JavaScript', + }), + mockRuleDetails({ + key: RULE_4, + type: 'BUG', + lang: 'c', + langName: 'C', + name: 'Awsome C rule', + }), + mockRuleDetails({ + key: RULE_5, + type: 'VULNERABILITY', + lang: 'py', + langName: 'Python', + name: 'Awsome Python rule', + descriptionSections: [ + { key: RuleDescriptionSections.INTRODUCTION, content: introTitle }, + { key: RuleDescriptionSections.HOW_TO_FIX, content: rootCauseContent }, + { + key: RuleDescriptionSections.RESOURCES, + content: resourceContent, + }, + ], + }), + mockRuleDetails({ + key: RULE_6, + type: 'BUG', + lang: 'py', + langName: 'Python', + name: 'Bad Python rule', + isExternal: true, + descriptionSections: undefined, + }), + mockRuleDetails({ + key: RULE_7, + type: 'VULNERABILITY', + severity: 'MINOR', + lang: 'py', + langName: 'Python', + name: 'Python rule with context', + descriptionSections: [ + { + key: RuleDescriptionSections.INTRODUCTION, + content: 'Introduction to this rule with context', + }, + { + key: RuleDescriptionSections.HOW_TO_FIX, + content: 'This is how to fix for spring', + context: { key: 'spring', displayName: 'Spring' }, + }, + { + key: RuleDescriptionSections.HOW_TO_FIX, + content: 'This is how to fix for spring boot', + context: { key: 'spring_boot', displayName: 'Spring boot' }, + }, + { + key: RuleDescriptionSections.RESOURCES, + content: resourceContent, + }, + ], + }), + mockRuleDetails({ + key: RULE_8, + type: 'BUG', + severity: 'MINOR', + lang: 'py', + langName: 'Python', + tags: ['awesome'], + name: 'Template rule', + params: [ + { key: '1', type: 'TEXT', htmlDesc: 'html description for key 1' }, + { key: '2', type: 'NUMBER', defaultValue: 'default value for key 2' }, + ], + isTemplate: true, + }), + mockRuleDetails({ + key: RULE_9, + type: 'BUG', + severity: 'MINOR', + lang: 'py', + langName: 'Python', + tags: ['awesome', 'cute'], + name: 'Custom Rule based on rule8', + params: [ + { key: '1', type: 'TEXT', htmlDesc: 'html description for key 1' }, + { key: '2', type: 'NUMBER', defaultValue: 'default value for key 2' }, + ], + templateKey: 'rule8', + }), + mockRuleDetails({ + createdAt: '2022-12-16T17:26:54+0100', + key: RULE_10, + type: 'VULNERABILITY', + severity: 'MINOR', + lang: 'py', + langName: 'Python', + tags: ['awesome'], + name: 'Awesome Python rule with education principles', + descriptionSections: [ + { key: RuleDescriptionSections.INTRODUCTION, content: introTitle }, + { key: RuleDescriptionSections.HOW_TO_FIX, content: rootCauseContent }, + { + key: RuleDescriptionSections.RESOURCES, + content: resourceContent, + }, + ], + educationPrinciples: ['defense_in_depth', 'never_trust_user_input'], + }), + mockRuleDetails({ + key: RULE_11, + type: 'BUG', + lang: 'java', + langName: 'Java', + name: 'Common java rule', + }), + ]; +} + +export function mockRulesActivationsInQP() { + return { + [RULE_1]: [mockRuleActivation({ qProfile: 'p1' })], + }; +} -- 2.39.5