Skip to content

Commit

Permalink
broke apart files (#130345)
Browse files Browse the repository at this point in the history
## Summary

Breaks apart the e2e FTR utils from one large file to individual files with an index.ts

### 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
  • Loading branch information
FrankHassanabad authored Apr 14, 2022
1 parent ef7f28e commit 874bfb3
Show file tree
Hide file tree
Showing 84 changed files with 3,045 additions and 2,179 deletions.
2,179 changes: 0 additions & 2,179 deletions x-pack/test/detection_engine_api_integration/utils.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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.
*/

/**
* Useful for export_api testing to convert from a multi-part binary back to a string
* @param res Response
* @param callback Callback
*/
export const binaryToString = (res: any, callback: any): void => {
res.setEncoding('binary');
res.data = '';
res.on('data', (chunk: any) => {
res.data += chunk;
});
res.on('end', () => {
callback(null, Buffer.from(res.data));
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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 { TransportResult } from '@elastic/elasticsearch';
import type { ToolingLog } from '@kbn/dev-utils';
import { countDownTest } from './count_down_test';

/**
* Does a plain countdown and checks against es queries for either conflicts in the error
* or for any over the wire issues such as timeouts or temp 404's to make the tests more
* reliant.
* @param esFunction The function to test against
* @param esFunctionName The name of the function to print if we encounter errors
* @param log The tooling logger
* @param retryCount The number of times to retry before giving up (has default)
* @param timeoutWait Time to wait before trying again (has default)
*/
export const countDownES = async (
esFunction: () => Promise<TransportResult<Record<string, any>, unknown>>,
esFunctionName: string,
log: ToolingLog,
retryCount: number = 50,
timeoutWait = 250
): Promise<void> => {
await countDownTest(
async () => {
const result = await esFunction();
if (result.body.version_conflicts !== 0) {
return {
passed: false,
errorMessage: 'Version conflicts for ${result.body.version_conflicts}',
};
} else {
return { passed: true };
}
},
esFunctionName,
log,
retryCount,
timeoutWait
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* 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 { ToolingLog } from '@kbn/dev-utils';

/**
* Does a plain countdown and checks against a boolean to determine if to wait and try again.
* This is useful for over the wire things that can cause issues such as conflict or timeouts
* for testing resiliency.
* @param functionToTest The function to test against
* @param name The name of the function to print if we encounter errors
* @param log The tooling logger
* @param retryCount The number of times to retry before giving up (has default)
* @param timeoutWait Time to wait before trying again (has default)
*/
export const countDownTest = async <T>(
functionToTest: () => Promise<{
passed: boolean;
returnValue?: T | undefined;
errorMessage?: string;
}>,
name: string,
log: ToolingLog,
retryCount: number = 50,
timeoutWait = 250,
ignoreThrow: boolean = false
): Promise<T | undefined> => {
if (retryCount > 0) {
try {
const testReturn = await functionToTest();
if (!testReturn.passed) {
const error = testReturn.errorMessage != null ? ` error: ${testReturn.errorMessage},` : '';
log.error(`Failure trying to ${name},${error} retries left are: ${retryCount - 1}`);
// retry, counting down, and delay a bit before
await new Promise((resolve) => setTimeout(resolve, timeoutWait));
const returnValue = await countDownTest(
functionToTest,
name,
log,
retryCount - 1,
timeoutWait,
ignoreThrow
);
return returnValue;
} else {
return testReturn.returnValue;
}
} catch (err) {
if (ignoreThrow) {
throw err;
} else {
log.error(
`Failure trying to ${name}, with exception message of: ${
err.message
}, retries left are: ${retryCount - 1}`
);
// retry, counting down, and delay a bit before
await new Promise((resolve) => setTimeout(resolve, timeoutWait));
const returnValue = await countDownTest(
functionToTest,
name,
log,
retryCount - 1,
timeoutWait,
ignoreThrow
);
return returnValue;
}
}
} else {
log.error(`Could not ${name}, no retries are left`);
return undefined;
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* 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 { ToolingLog } from '@kbn/dev-utils';
import type SuperTest from 'supertest';
import type {
CreateExceptionListItemSchema,
ListArray,
NonEmptyEntriesArray,
OsTypeArray,
} from '@kbn/securitysolution-io-ts-list-types';

import { EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants';
import { createExceptionListItem } from './create_exception_list_item';
import { waitFor } from './wait_for';
import { createExceptionList } from './create_exception_list';

/**
* Convenience testing function where you can pass in just the endpoint entries and you will
* get a container created with the entries.
* @param supertest super test agent
* @param endpointEntries The endpoint entries to create the rule and exception list from
* @param osTypes The os types to optionally add or not to add to the container
*/
export const createContainerWithEndpointEntries = async (
supertest: SuperTest.SuperTest<SuperTest.Test>,
log: ToolingLog,
endpointEntries: Array<{
entries: NonEmptyEntriesArray;
osTypes: OsTypeArray | undefined;
}>
): Promise<ListArray> => {
// If not given any endpoint entries, return without any
if (endpointEntries.length === 0) {
return [];
}

// create the endpoint exception list container
// eslint-disable-next-line @typescript-eslint/naming-convention
const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, {
description: 'endpoint description',
list_id: 'endpoint_list',
name: 'endpoint_list',
type: 'endpoint',
});

// Add the endpoint exception list container to the backend
await Promise.all(
endpointEntries.map((endpointEntry) => {
const exceptionListItem: CreateExceptionListItemSchema = {
description: 'endpoint description',
entries: endpointEntry.entries,
list_id: 'endpoint_list',
name: 'endpoint_list',
os_types: endpointEntry.osTypes,
type: 'simple',
};
return createExceptionListItem(supertest, log, exceptionListItem);
})
);

// To reduce the odds of in-determinism and/or bugs we ensure we have
// the same length of entries before continuing.
await waitFor(
async () => {
const { body } = await supertest.get(`${EXCEPTION_LIST_ITEM_URL}/_find?list_id=${list_id}`);
return body.data.length === endpointEntries.length;
},
`within createContainerWithEndpointEntries ${EXCEPTION_LIST_ITEM_URL}/_find?list_id=${list_id}`,
log
);

return [
{
id,
list_id,
namespace_type,
type,
},
];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 { ToolingLog } from '@kbn/dev-utils';
import type SuperTest from 'supertest';
import type { CreateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types';
import type { ListArray, NonEmptyEntriesArray } from '@kbn/securitysolution-io-ts-list-types';

import { EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants';
import { createExceptionList } from './create_exception_list';
import { createExceptionListItem } from './create_exception_list_item';
import { waitFor } from './wait_for';

/**
* Convenience testing function where you can pass in just the endpoint entries and you will
* get a container created with the entries.
* @param supertest super test agent
* @param entries The entries to create the rule and exception list from
* @param osTypes The os types to optionally add or not to add to the container
*/
export const createContainerWithEntries = async (
supertest: SuperTest.SuperTest<SuperTest.Test>,
log: ToolingLog,
entries: NonEmptyEntriesArray[]
): Promise<ListArray> => {
// If not given any endpoint entries, return without any
if (entries.length === 0) {
return [];
}
// Create the rule exception list container
// eslint-disable-next-line @typescript-eslint/naming-convention
const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, {
description: 'some description',
list_id: 'some-list-id',
name: 'some name',
type: 'detection',
});

// Add the rule exception list container to the backend
await Promise.all(
entries.map((entry) => {
const exceptionListItem: CreateExceptionListItemSchema = {
description: 'some description',
list_id: 'some-list-id',
name: 'some name',
type: 'simple',
entries: entry,
};
return createExceptionListItem(supertest, log, exceptionListItem);
})
);

// To reduce the odds of in-determinism and/or bugs we ensure we have
// the same length of entries before continuing.
await waitFor(
async () => {
const { body } = await supertest.get(`${EXCEPTION_LIST_ITEM_URL}/_find?list_id=${list_id}`);
return body.data.length === entries.length;
},
`within createContainerWithEntries ${EXCEPTION_LIST_ITEM_URL}/_find?list_id=${list_id}`,
log
);

return [
{
id,
list_id,
namespace_type,
type,
},
];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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 { ToolingLog } from '@kbn/dev-utils';
import type SuperTest from 'supertest';
import type {
CreateExceptionListSchema,
ExceptionListSchema,
} from '@kbn/securitysolution-io-ts-list-types';

import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants';
import { deleteExceptionList } from './delete_exception_list';

/**
* Helper to cut down on the noise in some of the tests. This checks for
* an expected 200 still and does not try to any retries. Creates exception lists
* @param supertest The supertest deps
* @param exceptionList The exception list to create
* @param log The tooling logger
*/
export const createExceptionList = async (
supertest: SuperTest.SuperTest<SuperTest.Test>,
log: ToolingLog,
exceptionList: CreateExceptionListSchema
): Promise<ExceptionListSchema> => {
const response = await supertest
.post(EXCEPTION_LIST_URL)
.set('kbn-xsrf', 'true')
.send(exceptionList);

if (response.status === 409) {
if (exceptionList.list_id != null) {
log.error(
`When creating an exception list found an unexpected conflict (409) creating an exception list (createExceptionList), will attempt a cleanup and one time re-try. This usually indicates a bad cleanup or race condition within the tests: ${JSON.stringify(
response.body
)}, status: ${JSON.stringify(response.status)}`
);
await deleteExceptionList(supertest, log, exceptionList.list_id);
const secondResponseTry = await supertest
.post(EXCEPTION_LIST_URL)
.set('kbn-xsrf', 'true')
.send(exceptionList);
if (secondResponseTry.status !== 200) {
throw new Error(
`Unexpected non 200 ok when attempting to create an exception list (second try): ${JSON.stringify(
response.body
)}`
);
} else {
return secondResponseTry.body;
}
} else {
throw new Error('When creating an exception list found an unexpected conflict (404)');
}
} else if (response.status !== 200) {
throw new Error(
`Unexpected non 200 ok when attempting to create an exception list: ${JSON.stringify(
response.status
)}`
);
} else {
return response.body;
}
};
Loading

0 comments on commit 874bfb3

Please sign in to comment.