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.

ProjectActivityServiceMock.ts 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 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 { chunk, cloneDeep, uniqueId } from 'lodash';
  21. import { parseDate } from '../../helpers/dates';
  22. import { mockAnalysis, mockAnalysisEvent } from '../../helpers/mocks/project-activity';
  23. import { BranchParameters } from '../../types/branch-like';
  24. import { Analysis, ProjectAnalysisEventCategory } from '../../types/project-activity';
  25. import {
  26. changeEvent,
  27. createEvent,
  28. deleteAnalysis,
  29. deleteEvent,
  30. getAllTimeProjectActivity,
  31. getProjectActivity,
  32. } from '../projectActivity';
  33. jest.mock('../projectActivity');
  34. const PAGE_SIZE = 10;
  35. const DEFAULT_PAGE = 1;
  36. const UNKNOWN_PROJECT = 'unknown';
  37. const defaultAnalysesList = [
  38. mockAnalysis({
  39. key: 'AXJMbIUGPAOIsUIE3eNT',
  40. date: parseDate('2017-03-03T22:00:00.000Z').toDateString(),
  41. projectVersion: '1.1',
  42. buildString: '1.1.0.2',
  43. events: [
  44. mockAnalysisEvent({
  45. category: ProjectAnalysisEventCategory.Version,
  46. key: 'IsUIEAXJMbIUGPAO3eND',
  47. name: '1.1',
  48. }),
  49. ],
  50. }),
  51. mockAnalysis({
  52. key: 'AXJMbIUGPAOIsUIE3eND',
  53. date: parseDate('2017-03-02T22:00:00.000Z').toDateString(),
  54. projectVersion: '1.1',
  55. buildString: '1.1.0.1',
  56. }),
  57. mockAnalysis({
  58. key: 'AXJMbIUGPAOIsUIE3eNE',
  59. date: parseDate('2017-03-01T22:00:00.000Z').toDateString(),
  60. projectVersion: '1.0',
  61. events: [
  62. mockAnalysisEvent({
  63. category: ProjectAnalysisEventCategory.Version,
  64. key: 'IUGPAOAXJMbIsUIE3eNE',
  65. name: '1.0',
  66. }),
  67. ],
  68. }),
  69. mockAnalysis({
  70. key: 'AXJMbIUGPAOIsUIE3eNC',
  71. date: parseDate('2017-02-28T22:00:00.000Z').toDateString(),
  72. projectVersion: '1.0',
  73. buildString: '1.0.0.1',
  74. }),
  75. ];
  76. export class ProjectActivityServiceMock {
  77. #analysisList: Analysis[];
  78. constructor() {
  79. this.#analysisList = cloneDeep(defaultAnalysesList);
  80. jest.mocked(getProjectActivity).mockImplementation(this.getActivityHandler);
  81. jest
  82. .mocked(getAllTimeProjectActivity)
  83. .mockImplementation(this.getAllTimeProjectActivityHandler);
  84. jest.mocked(deleteAnalysis).mockImplementation(this.deleteAnalysisHandler);
  85. jest.mocked(createEvent).mockImplementation(this.createEventHandler);
  86. jest.mocked(changeEvent).mockImplementation(this.changeEventHandler);
  87. jest.mocked(deleteEvent).mockImplementation(this.deleteEventHandler);
  88. }
  89. reset = () => {
  90. this.#analysisList = cloneDeep(defaultAnalysesList);
  91. };
  92. getAnalysesList = () => {
  93. return this.#analysisList;
  94. };
  95. setAnalysesList = (analyses: Analysis[]) => {
  96. this.#analysisList = analyses;
  97. };
  98. getActivityHandler = (
  99. data: {
  100. project: string;
  101. statuses?: string;
  102. category?: string;
  103. from?: string;
  104. p?: number;
  105. ps?: number;
  106. } & BranchParameters,
  107. ) => {
  108. const { project, ps = PAGE_SIZE, p = DEFAULT_PAGE, category, from } = data;
  109. if (project === UNKNOWN_PROJECT) {
  110. throw new Error(`Could not find project "${UNKNOWN_PROJECT}"`);
  111. }
  112. let analyses = category
  113. ? this.#analysisList.filter((a) => a.events.some((e) => e.category === category))
  114. : this.#analysisList;
  115. if (from !== undefined) {
  116. const fromTime = parseDate(from).getTime();
  117. analyses = analyses.filter((a) => parseDate(a.date).getTime() >= fromTime);
  118. }
  119. const analysesChunked = chunk(analyses, ps);
  120. return this.reply({
  121. paging: { pageSize: ps, total: analyses.length, pageIndex: p },
  122. analyses: analysesChunked[p - 1] ?? [],
  123. });
  124. };
  125. getAllTimeProjectActivityHandler = (
  126. data: {
  127. project: string;
  128. statuses?: string;
  129. category?: string;
  130. from?: string;
  131. p?: number;
  132. ps?: number;
  133. } & BranchParameters,
  134. ) => {
  135. const { project, p = DEFAULT_PAGE, category, from } = data;
  136. if (project === UNKNOWN_PROJECT) {
  137. throw new Error(`Could not find project "${UNKNOWN_PROJECT}"`);
  138. }
  139. let analyses = category
  140. ? this.#analysisList.filter((a) => a.events.some((e) => e.category === category))
  141. : this.#analysisList;
  142. if (from !== undefined) {
  143. const fromTime = parseDate(from).getTime();
  144. analyses = analyses.filter((a) => parseDate(a.date).getTime() >= fromTime);
  145. }
  146. return this.reply({
  147. paging: { pageSize: PAGE_SIZE, total: this.#analysisList.length, pageIndex: p },
  148. analyses: this.#analysisList,
  149. });
  150. };
  151. deleteAnalysisHandler = (analysisKey: string) => {
  152. const i = this.#analysisList.findIndex(({ key }) => key === analysisKey);
  153. if (i === undefined) {
  154. throw new Error(`Could not find analysis with key: ${analysisKey}`);
  155. }
  156. this.#analysisList.splice(i, 1);
  157. return this.reply(undefined);
  158. };
  159. createEventHandler = (data: {
  160. analysis: string;
  161. name: string;
  162. category?: ProjectAnalysisEventCategory;
  163. description?: string;
  164. }) => {
  165. const {
  166. analysis: analysisKey,
  167. name,
  168. category = ProjectAnalysisEventCategory.Other,
  169. description,
  170. } = data;
  171. const analysis = this.findAnalysis(analysisKey);
  172. const key = uniqueId(analysisKey);
  173. analysis.events.push({ key, name, category, description });
  174. return this.reply({
  175. analysis: analysisKey,
  176. key,
  177. name,
  178. category,
  179. description,
  180. });
  181. };
  182. changeEventHandler = (data: { event: string; name: string; description?: string }) => {
  183. const { event: eventKey, name, description } = data;
  184. const [eventIndex, analysisKey] = this.findEvent(eventKey);
  185. const analysis = this.findAnalysis(analysisKey);
  186. const event = analysis.events[eventIndex];
  187. event.name = name;
  188. event.description = description;
  189. return this.reply({ analysis: analysisKey, ...event });
  190. };
  191. deleteEventHandler = (eventKey: string) => {
  192. const [eventIndex, analysisKey] = this.findEvent(eventKey);
  193. const analysis = this.findAnalysis(analysisKey);
  194. analysis.events.splice(eventIndex, 1);
  195. return this.reply(undefined);
  196. };
  197. findEvent = (eventKey: string): [number, string] => {
  198. let analysisKey;
  199. const eventIndex = this.#analysisList.reduce((acc, { key, events }) => {
  200. if (acc === undefined) {
  201. const i = events.findIndex(({ key }) => key === eventKey);
  202. if (i > -1) {
  203. analysisKey = key;
  204. return i;
  205. }
  206. }
  207. return acc;
  208. }, undefined);
  209. if (eventIndex !== undefined && analysisKey !== undefined) {
  210. return [eventIndex, analysisKey];
  211. }
  212. throw new Error(`Could not find event with key: ${eventKey}`);
  213. };
  214. findAnalysis = (analysisKey: string) => {
  215. const analysis = this.#analysisList.find(({ key }) => key === analysisKey);
  216. if (analysis !== undefined) {
  217. return analysis;
  218. }
  219. throw new Error(`Could not find analysis with key: ${analysisKey}`);
  220. };
  221. reply<T>(response: T): Promise<T> {
  222. return Promise.resolve(cloneDeep(response));
  223. }
  224. }