You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SecurityHotspotServiceMock.ts 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. import { cloneDeep, times } from 'lodash';
  21. import {
  22. mockHotspot,
  23. mockHotspotComment,
  24. mockHotspotRule,
  25. mockRawHotspot,
  26. mockStandards,
  27. } from '../../helpers/mocks/security-hotspots';
  28. import { mockSourceLine } from '../../helpers/mocks/sources';
  29. import { getStandards } from '../../helpers/security-standard';
  30. import { mockPaging, mockRestUser } from '../../helpers/testMocks';
  31. import {
  32. Hotspot,
  33. HotspotAssignRequest,
  34. HotspotComment,
  35. HotspotResolution,
  36. HotspotStatus,
  37. } from '../../types/security-hotspots';
  38. import { RestUser } from '../../types/users';
  39. import { getSources } from '../components';
  40. import { getMeasures } from '../measures';
  41. import {
  42. assignSecurityHotspot,
  43. commentSecurityHotspot,
  44. deleteSecurityHotspotComment,
  45. editSecurityHotspotComment,
  46. getSecurityHotspotDetails,
  47. getSecurityHotspotList,
  48. getSecurityHotspots,
  49. setSecurityHotspotStatus,
  50. } from '../security-hotspots';
  51. import { getUsers } from '../users';
  52. const NUMBER_OF_LINES = 20;
  53. export default class SecurityHotspotServiceMock {
  54. hotspots: Hotspot[] = [];
  55. nextAssignee: string | undefined;
  56. canChangeStatus: boolean = true;
  57. hotspotsComments: HotspotComment[] = [];
  58. constructor() {
  59. this.reset();
  60. jest.mocked(getMeasures).mockImplementation(this.handleGetMeasures);
  61. jest.mocked(getSecurityHotspots).mockImplementation(this.handleGetSecurityHotspots);
  62. jest.mocked(getSecurityHotspotDetails).mockImplementation(this.handleGetSecurityHotspotDetails);
  63. jest.mocked(getSecurityHotspotList).mockImplementation(this.handleGetSecurityHotspotList);
  64. jest.mocked(assignSecurityHotspot).mockImplementation(this.handleAssignSecurityHotspot);
  65. jest.mocked(setSecurityHotspotStatus).mockImplementation(this.handleSetSecurityHotspotStatus);
  66. jest.mocked(getUsers).mockImplementation((p) => this.handleGetUsers(p));
  67. jest.mocked(getSources).mockResolvedValue(
  68. times(NUMBER_OF_LINES, (n) =>
  69. mockSourceLine({
  70. line: n,
  71. code: ' <span class="sym-35 sym">symbole</span>',
  72. })
  73. )
  74. );
  75. jest.mocked(commentSecurityHotspot).mockImplementation(this.handleCommentSecurityHotspot);
  76. jest
  77. .mocked(deleteSecurityHotspotComment)
  78. .mockImplementation(this.handleDeleteSecurityHotspotComment);
  79. jest
  80. .mocked(editSecurityHotspotComment)
  81. .mockImplementation(this.handleEditSecurityHotspotComment);
  82. jest.mocked(getStandards).mockImplementation(this.handleGetStandards);
  83. }
  84. handleCommentSecurityHotspot = () => {
  85. this.hotspotsComments = [
  86. mockHotspotComment({
  87. htmlText: 'This is a comment from john doe',
  88. markdown: 'This is a comment from john doe',
  89. updatable: true,
  90. }),
  91. ];
  92. return Promise.resolve();
  93. };
  94. handleDeleteSecurityHotspotComment = () => {
  95. this.hotspotsComments = [];
  96. return Promise.resolve();
  97. };
  98. handleEditSecurityHotspotComment = () => {
  99. const response = mockHotspotComment({
  100. htmlText: 'This is a comment from john doe test',
  101. markdown: 'This is a comment from john doe test',
  102. updatable: true,
  103. });
  104. this.hotspotsComments = [response];
  105. return Promise.resolve(response);
  106. };
  107. handleGetStandards = () => {
  108. return Promise.resolve(mockStandards());
  109. };
  110. handleSetSecurityHotspotStatus = () => {
  111. return Promise.resolve();
  112. };
  113. handleGetUsers: typeof getUsers<RestUser> = () => {
  114. return this.reply({
  115. users: [
  116. mockRestUser({ name: 'User John', login: 'user.john' }),
  117. mockRestUser({ name: 'User Doe', login: 'user.doe' }),
  118. mockRestUser({ name: 'User Foo', login: 'user.foo' }),
  119. ],
  120. page: mockPaging(),
  121. });
  122. };
  123. handleGetSecurityHotspotList = (
  124. hotspotKeys: string[],
  125. data: {
  126. projectKey: string;
  127. branch?: string;
  128. }
  129. ) => {
  130. if (data?.branch === 'normal-branch') {
  131. return this.reply({
  132. paging: mockPaging(),
  133. hotspots: [
  134. mockRawHotspot({
  135. assignee: 'John Doe',
  136. key: 'b1-test-1',
  137. message: "'F' is a magic number.",
  138. }),
  139. mockRawHotspot({ assignee: 'John Doe', key: 'b1-test-2' }),
  140. ].filter((h) => hotspotKeys.includes(h.key) || hotspotKeys.length === 0),
  141. components: [
  142. {
  143. key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed:index.php',
  144. qualifier: 'FIL',
  145. name: 'index.php',
  146. longName: 'index.php',
  147. path: 'index.php',
  148. },
  149. {
  150. key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed',
  151. qualifier: 'TRK',
  152. name: 'benflix',
  153. longName: 'benflix',
  154. },
  155. ],
  156. });
  157. }
  158. return this.reply({
  159. paging: mockPaging(),
  160. hotspots: this.mockRawHotspots(false).filter(
  161. (h) => hotspotKeys.includes(h.key) || hotspotKeys.length === 0
  162. ),
  163. components: [
  164. {
  165. key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed:index.php',
  166. qualifier: 'FIL',
  167. name: 'index.php',
  168. longName: 'index.php',
  169. path: 'index.php',
  170. },
  171. {
  172. key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed',
  173. qualifier: 'TRK',
  174. name: 'benflix',
  175. longName: 'benflix',
  176. },
  177. ],
  178. });
  179. };
  180. handleGetSecurityHotspots = (data: {
  181. projectKey: string;
  182. p: number;
  183. ps: number;
  184. status?: HotspotStatus;
  185. resolution?: HotspotResolution;
  186. onlyMine?: boolean;
  187. inNewCodePeriod?: boolean;
  188. branch?: string;
  189. }) => {
  190. if (data?.branch === 'normal-branch') {
  191. return this.reply({
  192. paging: mockPaging({ pageIndex: 1, pageSize: data.ps, total: 2 }),
  193. hotspots: [
  194. mockRawHotspot({
  195. assignee: 'John Doe',
  196. key: 'b1-test-1',
  197. message: "'F' is a magic number.",
  198. }),
  199. mockRawHotspot({ assignee: 'John Doe', key: 'b1-test-2' }),
  200. ],
  201. components: [
  202. {
  203. key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed:index.php',
  204. qualifier: 'FIL',
  205. name: 'index.php',
  206. longName: 'index.php',
  207. path: 'index.php',
  208. },
  209. {
  210. key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed',
  211. qualifier: 'TRK',
  212. name: 'benflix',
  213. longName: 'benflix',
  214. },
  215. ],
  216. });
  217. }
  218. return this.reply({
  219. paging: mockPaging({ pageIndex: 1, pageSize: data.ps, total: this.hotspots.length }),
  220. hotspots: this.mockRawHotspots(data.onlyMine),
  221. components: [
  222. {
  223. key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed:index.php',
  224. qualifier: 'FIL',
  225. name: 'index.php',
  226. longName: 'index.php',
  227. path: 'index.php',
  228. },
  229. {
  230. key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed',
  231. qualifier: 'TRK',
  232. name: 'benflix',
  233. longName: 'benflix',
  234. },
  235. ],
  236. });
  237. };
  238. mockRawHotspots = (onlyMine: boolean | undefined) => {
  239. if (onlyMine) {
  240. return [];
  241. }
  242. return [
  243. mockRawHotspot({ assignee: 'John Doe', key: 'test-1' }),
  244. mockRawHotspot({ assignee: 'John Doe', key: 'test-2' }),
  245. ];
  246. };
  247. handleGetSecurityHotspotDetails = (securityHotspotKey: string) => {
  248. const hotspot = this.hotspots.find((h) => h.key === securityHotspotKey);
  249. if (hotspot === undefined) {
  250. return Promise.reject({
  251. errors: [{ msg: `No security hotspot for key ${securityHotspotKey}` }],
  252. });
  253. }
  254. if (this.nextAssignee !== undefined) {
  255. hotspot.assigneeUser = {
  256. ...hotspot.assigneeUser,
  257. login: this.nextAssignee,
  258. name: this.nextAssignee,
  259. };
  260. this.nextAssignee = undefined;
  261. }
  262. hotspot.canChangeStatus = this.canChangeStatus;
  263. hotspot.comment = this.hotspotsComments;
  264. return this.reply(hotspot);
  265. };
  266. handleGetMeasures = () => {
  267. return this.reply([
  268. {
  269. key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed',
  270. name: 'benflix',
  271. qualifier: 'TRK',
  272. metric: 'security_hotspots_reviewed',
  273. measures: [{ metric: 'security_hotspots_reviewed', value: '0.0', bestValue: false }],
  274. },
  275. ]);
  276. };
  277. handleAssignSecurityHotspot = (_: string, data: HotspotAssignRequest) => {
  278. this.nextAssignee = data.assignee;
  279. return Promise.resolve();
  280. };
  281. setHotspotChangeStatusPermission = (value: boolean) => (this.canChangeStatus = value);
  282. reply<T>(response: T): Promise<T> {
  283. return Promise.resolve(cloneDeep(response));
  284. }
  285. reset = () => {
  286. this.hotspots = [
  287. mockHotspot({
  288. rule: mockHotspotRule({ key: 'rule2' }),
  289. assignee: 'John Doe',
  290. key: 'b1-test-1',
  291. message: "'F' is a magic number.",
  292. }),
  293. mockHotspot({
  294. rule: mockHotspotRule({ key: 'rule2' }),
  295. assignee: 'John Doe',
  296. key: 'b1-test-2',
  297. }),
  298. mockHotspot({
  299. rule: mockHotspotRule({ key: 'rule2' }),
  300. key: 'test-1',
  301. status: HotspotStatus.TO_REVIEW,
  302. }),
  303. mockHotspot({
  304. rule: mockHotspotRule({ key: 'rule2' }),
  305. key: 'test-2',
  306. status: HotspotStatus.TO_REVIEW,
  307. message: "'2' is a magic number.",
  308. codeVariants: ['variant 1', 'variant 2'],
  309. }),
  310. ];
  311. this.canChangeStatus = true;
  312. };
  313. }