From 91268e835c7137a4e572153834628f634a935267 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Mon, 27 Jan 2025 12:04:39 +0100 Subject: [PATCH] [SecuritySolution][Timelines/Notes] Updating API tests (#208218) ## Summary In this PR we're updating some API tests to use the OpenAPI-generated types and we're unksipping a bunch of tests on ESS. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Elastic Machine --- .../timelines/persist_favorite/index.ts | 2 +- .../timeline/tests/notes_privileges.ts | 20 +- .../investigation/timeline/tests/timeline.ts | 75 +++--- .../timeline/tests/timeline_privileges.ts | 66 ++++-- .../test_suites/investigation/utils/notes.ts | 61 +++-- .../investigation/utils/timelines.ts | 218 ++++++++++++------ .../test_suites/investigation/utils/types.ts | 10 + 7 files changed, 291 insertions(+), 161 deletions(-) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/investigation/utils/types.ts diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/timeline/routes/timelines/persist_favorite/index.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/timeline/routes/timelines/persist_favorite/index.ts index 31d80eebcf9aa..54c08667edd92 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/timeline/routes/timelines/persist_favorite/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/timeline/routes/timelines/persist_favorite/index.ts @@ -28,7 +28,7 @@ export const persistFavoriteRoute = (router: SecuritySolutionPluginRouter) => { path: TIMELINE_FAVORITE_URL, security: { authz: { - requiredPrivileges: ['timeline_read'], + requiredPrivileges: ['timeline_write'], }, }, access: 'public', diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/notes_privileges.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/notes_privileges.ts index f0f7c36b924f3..4e41fd8d61bf7 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/notes_privileges.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/notes_privileges.ts @@ -53,7 +53,9 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { before(async () => { const superTest = await utils.createSuperTestWithUser(users.secNotesAllUser); const { - body: { noteId }, + body: { + note: { noteId }, + }, } = await createNote(superTest, { text: 'test', documentId: '123' }); getNoteId = () => noteId; }); @@ -61,14 +63,16 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { canWriteOrReadUsers.forEach((user) => { it(`user "${user.username}" can read notes`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await getNote(superTest, getNoteId()).expect(200); + const getNoteResponse = await getNote(superTest, getNoteId()); + expect(getNoteResponse.status).to.be(200); }); }); cannotAccessUsers.forEach((user) => { it(`user "${user.username}" cannot read notes`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await getNote(superTest, getNoteId()).expect(403); + const getNoteResponse = await getNote(superTest, getNoteId()); + expect(getNoteResponse.status).to.be(403); }); }); }); @@ -96,7 +100,9 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { before(async () => { const superTest = await utils.createSuperTestWithUser(users.secNotesAllUser); const { - body: { noteId }, + body: { + note: { noteId }, + }, } = await createNote(superTest, { text: 'test', documentId: '123' }); getNoteId = () => noteId; }); @@ -104,14 +110,16 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { canWriteUsers.forEach((user) => { it(`user "${user.username}" can delete notes`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await deleteNote(superTest, getNoteId()).expect(200); + const deleteNoteRequest = await deleteNote(superTest, getNoteId()); + expect(deleteNoteRequest.status).to.be(200); }); }); cannotWriteUsers.forEach((user) => { it(`user "${user.username}" cannot delete notes`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await deleteNote(superTest, getNoteId()).expect(403); + const deleteNoteRequest = await deleteNote(superTest, getNoteId()); + expect(deleteNoteRequest.status).to.be(403); }); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline.ts index 5a0b79174293f..f09ddc9d221d8 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline.ts @@ -6,11 +6,15 @@ */ import expect from '@kbn/expect'; -import { SavedTimeline, TimelineTypeEnum } from '@kbn/security-solution-plugin/common/api/timeline'; -import { TIMELINE_URL, TIMELINES_URL } from '@kbn/security-solution-plugin/common/constants'; +import { TimelineTypeEnum } from '@kbn/security-solution-plugin/common/api/timeline'; import TestAgent from 'supertest/lib/agent'; import { FtrProviderContextWithSpaces } from '../../../../ftr_provider_context_with_spaces'; -import { createBasicTimeline, createBasicTimelineTemplate } from '../../utils/timelines'; +import { + createBasicTimeline, + createBasicTimelineTemplate, + getTimelines, + resolveTimeline, +} from '../../utils/timelines'; export default function ({ getService }: FtrProviderContextWithSpaces) { const utils = getService('securitySolutionUtils'); @@ -25,9 +29,9 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { const titleToSaved = 'hello timeline'; await createBasicTimeline(supertest, titleToSaved); - const resp = await supertest.get(TIMELINES_URL).set('kbn-xsrf', 'true'); - - const timelines = resp.body.timeline; + const { + body: { timeline: timelines }, + } = await getTimelines(supertest); expect(timelines.length).to.greaterThan(0); }); @@ -36,11 +40,9 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { const titleToSaved = 'hello timeline'; await createBasicTimeline(supertest, titleToSaved); - const resp = await supertest - .get(`${TIMELINES_URL}?page_size=1&page_index=1`) - .set('kbn-xsrf', 'true'); - - const timelines = resp.body.timeline; + const { + body: { timeline: timelines }, + } = await getTimelines(supertest, { page_size: '1', page_index: '1' }); expect(timelines.length).to.equal(1); }); @@ -49,11 +51,9 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { const titleToSaved = 'hello timeline template'; await createBasicTimelineTemplate(supertest, titleToSaved); - const resp = await supertest - .get(`${TIMELINES_URL}?timeline_type=template`) - .set('kbn-xsrf', 'true'); - - const templates: SavedTimeline[] = resp.body.timeline; + const { + body: { timeline: templates }, + } = await getTimelines(supertest, { timeline_type: 'template' }); expect(templates.length).to.greaterThan(0); expect( @@ -65,7 +65,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { * Migration of saved object not working to current serverless version * https://github.com/elastic/kibana/issues/196483 * */ - describe.skip('resolve timeline', () => { + describe('@skipInServerless resolve timeline', () => { before(async () => { await esArchiver.load( 'x-pack/test/functional/es_archives/security_solution/timelines/7.15.0' @@ -79,32 +79,25 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }); it('should return outcome exactMatch when the id is unchanged', async () => { - const resp = await supertest - .get(`${TIMELINE_URL}/resolve`) - .query({ id: '8dc70950-1012-11ec-9ad3-2d7c6600c0f7' }); - expect(resp.body.data.outcome).to.be('exactMatch'); - expect(resp.body.data.alias_target_id).to.be(undefined); - expect(resp.body.data.timeline.title).to.be('Awesome Timeline'); + const resp = await resolveTimeline(supertest, '8dc70950-1012-11ec-9ad3-2d7c6600c0f7'); + expect(resp.body.outcome).to.be('exactMatch'); + expect(resp.body.alias_target_id).to.be(undefined); + expect(resp.body.timeline.title).to.be('Awesome Timeline'); }); describe('notes', () => { it('should return notes with eventId', async () => { - const resp = await supertest - .get(`${TIMELINE_URL}/resolve`) - .query({ id: '6484cc90-126e-11ec-83d2-db1096c73738' }); - - expect(resp.body.data.timeline.notes[0].eventId).to.be('Edo00XsBEVtyvU-8LGNe'); + const resp = await resolveTimeline(supertest, '6484cc90-126e-11ec-83d2-db1096c73738'); + expect(resp.body.timeline.notes![0].eventId).to.be('Edo00XsBEVtyvU-8LGNe'); }); it('should return notes with the timelineId matching request id', async () => { - const resp = await supertest - .get(`${TIMELINE_URL}/resolve`) - .query({ id: '6484cc90-126e-11ec-83d2-db1096c73738' }); + const resp = await resolveTimeline(supertest, '6484cc90-126e-11ec-83d2-db1096c73738'); - expect(resp.body.data.timeline.notes[0].timelineId).to.be( + expect(resp.body.timeline.notes![0].timelineId).to.be( '6484cc90-126e-11ec-83d2-db1096c73738' ); - expect(resp.body.data.timeline.notes[1].timelineId).to.be( + expect(resp.body.timeline.notes![1].timelineId).to.be( '6484cc90-126e-11ec-83d2-db1096c73738' ); }); @@ -112,27 +105,23 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { describe('pinned events', () => { it('should pinned events with eventId', async () => { - const resp = await supertest - .get(`${TIMELINE_URL}/resolve`) - .query({ id: '6484cc90-126e-11ec-83d2-db1096c73738' }); + const resp = await resolveTimeline(supertest, '6484cc90-126e-11ec-83d2-db1096c73738'); - expect(resp.body.data.timeline.pinnedEventsSaveObject[0].eventId).to.be( + expect(resp.body.timeline.pinnedEventsSaveObject![0].eventId).to.be( 'DNo00XsBEVtyvU-8LGNe' ); - expect(resp.body.data.timeline.pinnedEventsSaveObject[1].eventId).to.be( + expect(resp.body.timeline.pinnedEventsSaveObject![1].eventId).to.be( 'Edo00XsBEVtyvU-8LGNe' ); }); it('should return pinned events with the timelineId matching request id', async () => { - const resp = await supertest - .get(`${TIMELINE_URL}/resolve`) - .query({ id: '6484cc90-126e-11ec-83d2-db1096c73738' }); + const resp = await resolveTimeline(supertest, '6484cc90-126e-11ec-83d2-db1096c73738'); - expect(resp.body.data.timeline.pinnedEventsSaveObject[0].timelineId).to.be( + expect(resp.body.timeline.pinnedEventsSaveObject![0].timelineId).to.be( '6484cc90-126e-11ec-83d2-db1096c73738' ); - expect(resp.body.data.timeline.pinnedEventsSaveObject[1].timelineId).to.be( + expect(resp.body.timeline.pinnedEventsSaveObject![1].timelineId).to.be( '6484cc90-126e-11ec-83d2-db1096c73738' ); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_privileges.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_privileges.ts index 7ee34ef482ec0..96e6f21e3651c 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_privileges.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_privileges.ts @@ -18,6 +18,7 @@ import { copyTimeline, resolveTimeline, installPrepackedTimelines, + unPinEvent, } from '../../utils/timelines'; import * as users from '../../../../config/privileges/users'; import { roles } from '../../../../config/privileges/roles'; @@ -63,14 +64,16 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { canWriteOrReadUsers.forEach((user) => { it(`user "${user.username}" can read timelines`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await getTimelines(superTest).expect(200); + const getTimelinesResponse = await getTimelines(superTest); + expect(getTimelinesResponse.status).to.be(200); }); }); cannotAccessUsers.forEach((user) => { it(`user "${user.username}" cannot read timelines`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await getTimelines(superTest).expect(403); + const getTimelinesResponse = await getTimelines(superTest); + expect(getTimelinesResponse.status).to.be(403); }); }); }); @@ -87,14 +90,16 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { canWriteOrReadUsers.forEach((user) => { it(`user "${user.username}" can resolve timelines`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await resolveTimeline(superTest, getTimelineId()).expect(200); + const resolveTimelineResponse = await resolveTimeline(superTest, getTimelineId()); + expect(resolveTimelineResponse.status).to.be(200); }); }); cannotAccessUsers.forEach((user) => { it(`user "${user.username}" cannot resolve timelines`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await resolveTimeline(superTest, getTimelineId()).expect(403); + const resolveTimelineResponse = await resolveTimeline(superTest, getTimelineId()); + expect(resolveTimelineResponse.status).to.be(403); }); }); }); @@ -107,7 +112,8 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { const createResponse = await createBasicTimeline(superTest, 'test timeline'); expect(createResponse.status).to.be(200); - await deleteTimeline(superTest, createResponse.body.savedObjectId).expect(200); + const deleteResponse = await deleteTimeline(superTest, createResponse.body.savedObjectId); + expect(deleteResponse.status).to.be(200); }); }); @@ -131,7 +137,8 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { it(`user "${user.username}" cannot delete timelines`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await deleteTimeline(superTest, getTimelineToDeleteId()).expect(403); + const deleteResponse = await deleteTimeline(superTest, getTimelineToDeleteId()); + expect(deleteResponse.status).to.be(403); }); }); }); @@ -185,10 +192,14 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { canWriteUsers.forEach((user) => { it(`user "${user.username}" can favorite/unfavorite timelines`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await favoriteTimeline(superTest, getTimelineId()).expect(200); + const favoriteTimelineRequest = await favoriteTimeline(superTest, getTimelineId()); + expect(favoriteTimelineRequest.status).to.be(200); + expect(favoriteTimelineRequest.body.favorite).to.have.length(1); // unfavorite - await favoriteTimeline(superTest, getTimelineId()).expect(200); + const unFavoriteTimelineRequest = await favoriteTimeline(superTest, getTimelineId()); + expect(unFavoriteTimelineRequest.status).to.be(200); + expect(unFavoriteTimelineRequest.body.favorite).to.have.length(0); }); }); @@ -196,7 +207,8 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { it(`user "${user.username}" cannot favorite/unfavorite timelines`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await favoriteTimeline(superTest, getTimelineId()).expect(403); + const favoriteTimelineRequest = await favoriteTimeline(superTest, getTimelineId()); + expect(favoriteTimelineRequest.status).to.be(403); }); }); }); @@ -214,10 +226,19 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { canWriteUsers.forEach((user) => { it(`user "${user.username}" can pin/unpin events`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await pinEvent(superTest, getTimelineId(), eventId).expect(200); + const pinEventResponse = await pinEvent(superTest, getTimelineId(), eventId); + expect(pinEventResponse.status).to.be(200); + expect('pinnedEventId' in pinEventResponse.body).to.be(true); // unpin - await pinEvent(superTest, getTimelineId(), eventId).expect(200); + const unPinEventResponse = await unPinEvent( + superTest, + getTimelineId(), + eventId, + 'pinnedEventId' in pinEventResponse.body ? pinEventResponse.body.pinnedEventId : '' + ); + expect(unPinEventResponse.status).to.be(200); + expect(unPinEventResponse.body).to.eql({ unpinned: true }); }); }); @@ -225,7 +246,8 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { it(`user "${user.username}" cannot pin/unpin events`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await pinEvent(superTest, getTimelineId(), eventId).expect(403); + const pinEventResponse = await pinEvent(superTest, getTimelineId(), eventId); + expect(pinEventResponse.status).to.be(403); }); }); }); @@ -242,7 +264,12 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { it(`user "${user.username}" can copy timeline`, async () => { const superTest = await utils.createSuperTestWithUser(user); const timeline = getTimeline(); - await copyTimeline(superTest, timeline.savedObjectId, timeline).expect(200); + const copyTimelineResponse = await copyTimeline( + superTest, + timeline.savedObjectId, + timeline + ); + expect(copyTimelineResponse.status).to.be(200); }); }); @@ -250,7 +277,12 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { it(`user "${user.username}" cannot copy timeline`, async () => { const superTest = await utils.createSuperTestWithUser(user); const timeline = getTimeline(); - await copyTimeline(superTest, timeline.savedObjectId, timeline).expect(403); + const copyTimelineResponse = await copyTimeline( + superTest, + timeline.savedObjectId, + timeline + ); + expect(copyTimelineResponse.status).to.be(403); }); }); }); @@ -259,14 +291,16 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { canWriteUsers.forEach((user) => { it(`user "${user.username}" can install prepackaged timelines`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await installPrepackedTimelines(superTest).expect(200); + const installTimelinesResponse = await installPrepackedTimelines(superTest); + expect(installTimelinesResponse.status).to.be(200); }); }); cannotWriteUsers.forEach((user) => { it(`user "${user.username}" cannot install prepackaged timelines`, async () => { const superTest = await utils.createSuperTestWithUser(user); - await installPrepackedTimelines(superTest).expect(403); + const installTimelinesResponse = await installPrepackedTimelines(superTest); + expect(installTimelinesResponse.status).to.be(403); }); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/utils/notes.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/utils/notes.ts index 57599ca28aef8..80222669e701a 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/utils/notes.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/utils/notes.ts @@ -7,12 +7,16 @@ import type SuperTest from 'supertest'; import { + DeleteNoteRequestBody, GetNotesResult, Note, PersistNoteRouteRequestBody, + PersistNoteRouteResponse, } from '@kbn/security-solution-plugin/common/api/timeline'; import { NOTE_URL } from '@kbn/security-solution-plugin/common/constants'; +import { type SuperTestResponse } from './types'; + /** * Deletes the first 100 notes (the getNotes endpoints is paginated and defaults to 10 is nothing is provided) * This works in ess, serverless and on the MKI environments as it avoids having to look at hidden indexes. @@ -24,12 +28,11 @@ export const deleteNotes = async (supertest: SuperTest.Agent): Promise => .set('elastic-api-version', '2023-10-31'); const { notes } = response.body as GetNotesResult; - await supertest - .delete(NOTE_URL) - .set('kbn-xsrf', 'true') - .send({ - noteIds: notes.map((note: Note) => note.noteId), - }); + const deleteNoteRequestBody: DeleteNoteRequestBody = { + noteIds: notes.map((note: Note) => note.noteId), + }; + + await supertest.delete(NOTE_URL).set('kbn-xsrf', 'true').send(deleteNoteRequestBody); }; /** @@ -47,26 +50,38 @@ export const createNote = async ( savedObjectId?: string; text: string; } -) => - await supertest - .patch(NOTE_URL) - .set('kbn-xsrf', 'true') - .send({ - note: { - eventId: note.documentId || '', - timelineId: note.savedObjectId || '', - note: note.text, - }, - } as PersistNoteRouteRequestBody); +): Promise> => { + const createNoteRequestBody: PersistNoteRouteRequestBody = { + note: { + eventId: note.documentId || '', + timelineId: note.savedObjectId || '', + note: note.text, + }, + }; + return await supertest.patch(NOTE_URL).set('kbn-xsrf', 'true').send(createNoteRequestBody); +}; -export const getNote = (supertest: SuperTest.Agent, noteId: string) => - supertest +export const getNote = async ( + supertest: SuperTest.Agent, + noteId: string +): Promise> => { + return await supertest .get(`${NOTE_URL}?noteId=${noteId}`) .set('kbn-xsrf', 'true') .set('elastic-api-version', '2023-10-31'); +}; -export const deleteNote = (supertest: SuperTest.Agent, noteId: string) => - supertest.delete(NOTE_URL).set('kbn-xsrf', 'true').set('elastic-api-version', '2023-10-31').send({ +export const deleteNote = async ( + supertest: SuperTest.Agent, + noteId: string +): Promise> => { + const deleteNoteRequestBody: DeleteNoteRequestBody = { noteId, - noteIds: null, - }); + }; + + return await supertest + .delete(NOTE_URL) + .set('kbn-xsrf', 'true') + .set('elastic-api-version', '2023-10-31') + .send(deleteNoteRequestBody); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/utils/timelines.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/utils/timelines.ts index 3b63b1a7b72fb..41f32e134b4ac 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/utils/timelines.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/utils/timelines.ts @@ -8,9 +8,20 @@ import type SuperTest from 'supertest'; import { v4 as uuidv4 } from 'uuid'; import { + CopyTimelineRequestBody, + CopyTimelineResponse, + CreateTimelinesRequestBody, + CreateTimelinesResponse, + DeleteTimelinesRequestBody, GetTimelinesResponse, + GetTimelinesRequestQuery, + PatchTimelineRequestBody, + PersistFavoriteRouteRequestBody, + PersistFavoriteRouteResponse, + PersistPinnedEventRouteRequestBody, + PersistPinnedEventResponse, + ResolveTimelineResponse, SavedTimeline, - SavedTimelineWithSavedObjectId, TimelineTypeEnum, } from '@kbn/security-solution-plugin/common/api/timeline'; import { @@ -23,114 +34,177 @@ import { TIMELINE_PREPACKAGED_URL, } from '@kbn/security-solution-plugin/common/constants'; +import { type SuperTestResponse } from './types'; + /** * Deletes the first 100 timelines. * This works in ess, serverless and on the MKI environments as it avoids having to look at hidden indexes. */ -export const deleteTimelines = async (supertest: SuperTest.Agent): Promise => { +export const deleteTimelines = async ( + supertest: SuperTest.Agent +): Promise> => { const response = await getTimelines(supertest); - const { timeline: timelines } = response.body as GetTimelinesResponse; + const { timeline: timelines } = response.body; + const deleteRequestBody: DeleteTimelinesRequestBody = { + savedObjectIds: timelines.map((timeline) => timeline.savedObjectId), + }; - await supertest - .delete(TIMELINE_URL) - .set('kbn-xsrf', 'true') - .send({ - savedObjectIds: timelines.map( - (timeline: SavedTimelineWithSavedObjectId) => timeline.savedObjectId - ), - }); + return await supertest.delete(TIMELINE_URL).set('kbn-xsrf', 'true').send(deleteRequestBody); }; -export const deleteTimeline = (supertest: SuperTest.Agent, savedObjectId: string) => - supertest - .delete(TIMELINE_URL) - .set('kbn-xsrf', 'true') - .send({ - savedObjectIds: [savedObjectId], - }); +export const deleteTimeline = async ( + supertest: SuperTest.Agent, + savedObjectId: string +): Promise> => { + const deleteRequestBody: DeleteTimelinesRequestBody = { + savedObjectIds: [savedObjectId], + }; + + return await supertest.delete(TIMELINE_URL).set('kbn-xsrf', 'true').send(deleteRequestBody); +}; export const patchTimeline = ( supertest: SuperTest.Agent, timelineId: string, version: string, - timelineObj: unknown -) => - supertest.patch(TIMELINE_URL).set('kbn-xsrf', 'true').send({ + timelineObj: SavedTimeline +) => { + const patchRequestBody: PatchTimelineRequestBody = { timelineId, version, timeline: timelineObj, - }); + }; + return supertest.patch(TIMELINE_URL).set('kbn-xsrf', 'true').send(patchRequestBody); +}; -export const createBasicTimeline = async (supertest: SuperTest.Agent, titleToSaved: string) => - await supertest - .post(TIMELINE_URL) - .set('kbn-xsrf', 'true') - .send({ - timelineId: null, - version: null, - timeline: { - title: titleToSaved, - }, - }); +export const createBasicTimeline = async ( + supertest: SuperTest.Agent, + titleToSaved: string +): Promise> => { + const createTimelineBody: CreateTimelinesRequestBody = { + timelineId: null, + version: null, + timeline: { + title: titleToSaved, + }, + }; + return await supertest.post(TIMELINE_URL).set('kbn-xsrf', 'true').send(createTimelineBody); +}; export const createBasicTimelineTemplate = async ( supertest: SuperTest.Agent, titleToSaved: string -) => - await supertest +): Promise> => { + const createTimelineTemplateBody: CreateTimelinesRequestBody = { + timelineId: null, + version: null, + timeline: { + title: titleToSaved, + templateTimelineId: uuidv4(), + templateTimelineVersion: 1, + timelineType: TimelineTypeEnum.template, + }, + }; + return await supertest .post(TIMELINE_URL) .set('kbn-xsrf', 'true') - .send({ - timelineId: null, - version: null, - timeline: { - title: titleToSaved, - templateTimelineId: uuidv4(), - templateTimelineVersion: 1, - timelineType: TimelineTypeEnum.template, - }, - }); - -export const getTimelines = (supertest: SuperTest.Agent) => - supertest.get(TIMELINES_URL).set('kbn-xsrf', 'true').set('elastic-api-version', '2023-10-31'); - -export const resolveTimeline = (supertest: SuperTest.Agent, timelineId: string) => - supertest + .send(createTimelineTemplateBody); +}; + +export const getTimelines = async ( + supertest: SuperTest.Agent, + options?: GetTimelinesRequestQuery +): Promise> => { + let url: string = TIMELINES_URL; + + if (options) { + url += '?'; + for (const [key, value] of Object.entries(options)) { + url += `${key}=${value}&`; + } + } + + return await supertest.get(url).set('kbn-xsrf', 'true').set('elastic-api-version', '2023-10-31'); +}; + +export const resolveTimeline = async ( + supertest: SuperTest.Agent, + timelineId: string +): Promise> => + await supertest .get(`${TIMELINE_RESOLVE_URL}?id=${timelineId}`) .set('kbn-xsrf', 'true') .set('elastic-api-version', '2023-10-31'); -export const favoriteTimeline = (supertest: SuperTest.Agent, timelineId: string) => - supertest +export const favoriteTimeline = async ( + supertest: SuperTest.Agent, + timelineId: string +): Promise> => { + const favoriteTimelineRequestBody: PersistFavoriteRouteRequestBody = { + timelineId, + templateTimelineId: null, + templateTimelineVersion: null, + timelineType: null, + }; + return await supertest .patch(TIMELINE_FAVORITE_URL) .set('kbn-xsrf', 'true') .set('elastic-api-version', '2023-10-31') - .send({ - timelineId, - templateTimelineId: null, - templateTimelineVersion: null, - timelineType: null, - }); - -export const pinEvent = (supertest: SuperTest.Agent, timelineId: string, eventId: string) => - supertest + .send(favoriteTimelineRequestBody); +}; + +export const pinEvent = async ( + supertest: SuperTest.Agent, + timelineId: string, + eventId: string +): Promise> => { + const pinEventRequestBody: PersistPinnedEventRouteRequestBody = { + timelineId, + eventId, + }; + return await supertest + .patch(PINNED_EVENT_URL) + .set('kbn-xsrf', 'true') + .set('elastic-api-version', '2023-10-31') + .send(pinEventRequestBody); +}; + +export const unPinEvent = async ( + supertest: SuperTest.Agent, + timelineId: string, + eventId: string, + pinnedEventId: string +): Promise> => { + const pinEventRequestBody: PersistPinnedEventRouteRequestBody = { + timelineId, + eventId, + pinnedEventId, + }; + return await supertest .patch(PINNED_EVENT_URL) .set('kbn-xsrf', 'true') .set('elastic-api-version', '2023-10-31') - .send({ - timelineId, - eventId, - }); + .send(pinEventRequestBody); +}; -export const copyTimeline = ( +export const copyTimeline = async ( supertest: SuperTest.Agent, timelineId: string, timelineObj: SavedTimeline -) => - supertest.post(TIMELINE_COPY_URL).set('kbn-xsrf', 'true').set('elastic-api-version', '1').send({ +): Promise> => { + const copyTimelineRequestBody: CopyTimelineRequestBody = { timelineIdToCopy: timelineId, timeline: timelineObj, - }); + }; + return supertest + .post(TIMELINE_COPY_URL) + .set('kbn-xsrf', 'true') + .set('elastic-api-version', '1') + .send(copyTimelineRequestBody); +}; -export const installPrepackedTimelines = (supertest: SuperTest.Agent) => - supertest.post(TIMELINE_PREPACKAGED_URL).set('kbn-xsrf', 'true').send(); +export const installPrepackedTimelines = async ( + supertest: SuperTest.Agent +): Promise> => { + return await supertest.post(TIMELINE_PREPACKAGED_URL).set('kbn-xsrf', 'true').send(); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/utils/types.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/utils/types.ts new file mode 100644 index 0000000000000..ec79a3ccd4ee3 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/utils/types.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type SuperTest from 'supertest'; + +export type SuperTestResponse = Omit & { body: T };