diff --git a/src/server/controllers/item/create-item-async-controller.ts b/src/server/controllers/item/create-item-async-controller.ts index 72194e89..5c8c9b14 100644 --- a/src/server/controllers/item/create-item-async-controller.ts +++ b/src/server/controllers/item/create-item-async-controller.ts @@ -10,12 +10,12 @@ import { generateShareToken } from "./utils/generateShareToken" import { upsertScenario } from "./shared/upsert-scenario" export const createItemAsyncController = async (req: IGetUserAuthInfoRequest, res: Response) => { - const { environment, note, status = ItemStatus.None, hostname, name, resourcesLink } = req.body + const { environment, note, status = ItemStatus.None, hostname, name, resourcesLink, keepTestRunsPeriod } = req.body const { scenarioName, projectName } = req.params logger.info(`Creating new item for scenario: ${scenarioName}`) try { - const scenarioExists = await upsertScenario(projectName, scenarioName) + const scenarioExists = await upsertScenario(projectName, scenarioName, keepTestRunsPeriod) if (!scenarioExists) { return res.status(StatusCode.NotFound).json({ message: "scenario not found" }) } diff --git a/src/server/controllers/item/create-item-controller.ts b/src/server/controllers/item/create-item-controller.ts index 333103bf..5eb9990b 100644 --- a/src/server/controllers/item/create-item-controller.ts +++ b/src/server/controllers/item/create-item-controller.ts @@ -24,6 +24,7 @@ import { TEST_NAME_MAX_LENGTH, } from "./create-item-const" import { AnalyticsEvent } from "../../utils/analytics/anyltics-event" +import { ALLOWED_PERIOD } from "./shared/constants" const pg = pgp() @@ -42,7 +43,7 @@ const SECONDS_DIVISOR = 1000 export const createItemController = (req: IGetUserAuthInfoRequest, res: Response, next: NextFunction) => { // eslint-disable-next-line complexity upload(req, res, async error => { - const { environment, note, status = ItemStatus.None, hostname, name, resourcesLink } = req.body + const { environment, note, status = ItemStatus.None, hostname, name, resourcesLink, keepTestRunsPeriod } = req.body if (!req.files) { return next(boom.badRequest()) } @@ -60,6 +61,12 @@ export const createItemController = (req: IGetUserAuthInfoRequest, res: Response if (!Object.values(ItemStatus).some(_ => _ === status)) { return next(boom.badRequest("invalid status type")) } + if (keepTestRunsPeriod) { + const keepTestRunsPeriodError = checkKeepTestRunsPeriod(keepTestRunsPeriod) + if (keepTestRunsPeriodError) { + return next(keepTestRunsPeriodError) + } + } const failedValidations = checkFieldsLength([ { name: "environment", value: environment, maxLength: ENVIRONMENT_MAX_LENGTH }, { name: "name", value: name, maxLength: TEST_NAME_MAX_LENGTH }, @@ -79,7 +86,7 @@ export const createItemController = (req: IGetUserAuthInfoRequest, res: Response const monitoringFileName = monitoring?.[0]?.path let tempBuffer = [] - await upsertScenario(projectName, scenarioName) + await upsertScenario(projectName, scenarioName, keepTestRunsPeriod) const item = await db.one(createNewItem( scenarioName, @@ -227,3 +234,19 @@ const checkFieldsLength = (properties: Array<{ name: string; value: any; maxLeng }) return failedValidations } + +export const checkKeepTestRunsPeriod = (keepTestRunsPeriod): boom => { + try { + const keepTestRunsPeriodNumber = parseInt(keepTestRunsPeriod, 10) + if (isNaN(keepTestRunsPeriodNumber)) { + return boom.badRequest("keepTestRunsPeriod - only numbers are allowed") + } + const allowedValue = ALLOWED_PERIOD.find(val => val === keepTestRunsPeriodNumber) + if (!allowedValue) { + return boom.badRequest(`invalid value, allowed values are: ${ALLOWED_PERIOD}`) + } + return + } catch(e) { + return boom.badRequest("keepTestRunsPeriod - only numbers are allowed") + } +} diff --git a/src/server/controllers/item/shared/constants.spec.ts b/src/server/controllers/item/shared/constants.spec.ts new file mode 100644 index 00000000..a7813cf6 --- /dev/null +++ b/src/server/controllers/item/shared/constants.spec.ts @@ -0,0 +1,8 @@ +import { ALLOWED_PERIOD } from "./constants" + +describe("ALLOWED_PERIOD", () => { + it("contains expected values", () => { + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + expect(ALLOWED_PERIOD).toEqual( [7, 14, 30, 90, 180] ) + }) +}) diff --git a/src/server/controllers/item/shared/constants.ts b/src/server/controllers/item/shared/constants.ts new file mode 100644 index 00000000..85f1325e --- /dev/null +++ b/src/server/controllers/item/shared/constants.ts @@ -0,0 +1,4 @@ +// eslint-disable-next-line @typescript-eslint/no-magic-numbers +export const ALLOWED_PERIOD = [7, 14, 30, 90, 180] // period in days, values expected by FE, if changed, the FE mapping will break + + diff --git a/src/server/controllers/item/shared/upsert-scenario.spec.ts b/src/server/controllers/item/shared/upsert-scenario.spec.ts index 3d499fba..4c39b38d 100644 --- a/src/server/controllers/item/shared/upsert-scenario.spec.ts +++ b/src/server/controllers/item/shared/upsert-scenario.spec.ts @@ -12,21 +12,21 @@ describe("upsertScenario", () => { (db.one as any).mockResolvedValueOnce({ upsertScenario: true }); (db.oneOrNone as any).mockResolvedValueOnce(null) const spy = jest.spyOn(require("../../../queries/scenario"), "createNewScenario") - await upsertScenario("projectName", "scenarioNAme") + await upsertScenario("projectName", "scenarioNAme", 0) expect(spy).toHaveBeenCalledTimes(1) - expect(spy).toHaveBeenCalledWith("projectName", "scenarioNAme") + expect(spy).toHaveBeenCalledWith("projectName", "scenarioNAme", 0) }) it("should not create scenario if it already exists and allowed by settings", async () => { (db.one as any).mockResolvedValueOnce({ upsertScenario: true }); (db.oneOrNone as any).mockResolvedValueOnce("scenarioName") const spy = jest.spyOn(require("../../../queries/scenario"), "createNewScenario") - await upsertScenario("projectName", "scenarioNAme") + await upsertScenario("projectName", "scenarioNAme", 0) expect(spy).toHaveBeenCalledTimes(0) }) it("should not create scenario if not allowed by settings", async () => { (db.one as any).mockResolvedValueOnce({ upsertScenario: false }) const spy = jest.spyOn(require("../../../queries/scenario"), "createNewScenario") - await upsertScenario("projectName", "scenarioNAme") + await upsertScenario("projectName", "scenarioNAme", 0) expect(spy).toHaveBeenCalledTimes(0) }) diff --git a/src/server/controllers/item/shared/upsert-scenario.ts b/src/server/controllers/item/shared/upsert-scenario.ts index ce0475c7..ee1b408b 100644 --- a/src/server/controllers/item/shared/upsert-scenario.ts +++ b/src/server/controllers/item/shared/upsert-scenario.ts @@ -3,7 +3,7 @@ import { getProject } from "../../../queries/projects" import { createNewScenario, getScenario } from "../../../queries/scenario" import { logger } from "../../../../logger" -export const upsertScenario = async (projectName, scenarioName) => { +export const upsertScenario = async (projectName, scenarioName, keepTestRunsPeriod: number) => { const scenario = await db.oneOrNone(getScenario(projectName, scenarioName)) if (scenario) { // scenario already exists @@ -12,7 +12,7 @@ export const upsertScenario = async (projectName, scenarioName) => { const project = await db.one(getProject(projectName)) if (project.upsertScenario) { logger.info(`Creating new scenario "${scenarioName}" into project "${projectName}"`) - await db.query(createNewScenario(projectName, scenarioName)) + await db.query(createNewScenario(projectName, scenarioName, keepTestRunsPeriod)) return true } return false diff --git a/src/server/queries/scenario.ts b/src/server/queries/scenario.ts index dfdb0fdf..1c66d8e0 100644 --- a/src/server/queries/scenario.ts +++ b/src/server/queries/scenario.ts @@ -93,12 +93,12 @@ export const deleteScenario = (projectName, scenarioName) => { } } -export const createNewScenario = (projectName, scenarioName) => { +export const createNewScenario = (projectName, scenarioName, keepTestRunsPeriod = 0) => { return { - text: `INSERT INTO jtl.scenario(name, project_id, analysis_enabled) VALUES($2, ( + text: `INSERT INTO jtl.scenario(name, project_id, analysis_enabled, keep_test_runs_period) VALUES($2, ( SELECT id FROM jtl.projects WHERE project_name = $1 - ), $3)`, - values: [projectName, scenarioName, true], + ), $3, $4)`, + values: [projectName, scenarioName, true, keepTestRunsPeriod], } } diff --git a/src/server/schema-validator/item-schema.ts b/src/server/schema-validator/item-schema.ts index 87cb13eb..741dd7c1 100644 --- a/src/server/schema-validator/item-schema.ts +++ b/src/server/schema-validator/item-schema.ts @@ -5,6 +5,7 @@ import { NOTE_MAX_LENGTH, RESOURCES_LINK_MAX_LENGTH, TEST_NAME_MAX_LENGTH, } from "../controllers/item/create-item-const" +import { ALLOWED_PERIOD } from "../controllers/item/shared/constants" const projectName = Joi.string().required() @@ -55,6 +56,7 @@ export const newAsyncItemStartBodySchema = Joi.object().keys({ hostname, note, resourcesLink, + keepTestRunsPeriod: Joi.number().valid(ALLOWED_PERIOD), }) export const newItemParamSchema = Joi.object().keys({