Skip to content

Commit

Permalink
Adds safe guards against in-determinism by checking list items after …
Browse files Browse the repository at this point in the history
…uploads (#84015)

## Summary

Fixes flakey tests by adding explicit list value upload items through either the fixture that was uploaded or by a specific test value in case the uploaded list is a range value. Also filters out any empty values for more safeguards from prettier formatters that add them to fixture files.

#84014

### 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 Nov 23, 2020
1 parent 0a0672f commit 24c7b2d
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ describe('value lists', () => {

it('deletes a "ip_range" from an uploaded file', () => {
const listName = 'cidr_list.txt';
importValueList(listName, 'ip_range');
importValueList(listName, 'ip_range', ['192.168.100.0']);
openValueListsModal();
deleteValueListsFile(listName);
cy.get(VALUE_LISTS_TABLE)
Expand Down Expand Up @@ -209,7 +209,7 @@ describe('value lists', () => {

it('exports a "ip_range" list from an uploaded file', () => {
const listName = 'cidr_list.txt';
importValueList(listName, 'ip_range');
importValueList(listName, 'ip_range', ['192.168.100.0']);
openValueListsModal();
exportValueList();
cy.wait('@exportList').then((xhr) => {
Expand Down
105 changes: 91 additions & 14 deletions x-pack/plugins/security_solution/cypress/tasks/lists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,27 +77,104 @@ export const deleteValueList = (list: string): Cypress.Chainable<Cypress.Respons
};

/**
* Imports a single value list file this using Cypress Request and lists REST API
* Uploads list items using Cypress Request and lists REST API.
*
* This also will remove any upload data such as empty strings that can happen from the fixture
* due to extra lines being added from formatters such as prettier.
* @param file The file name to import
* @param type The type of the file import such as ip/keyword/text etc...
* @param data The contents of the file
* @param testSuggestions The type of test to use rather than the fixture file which is useful for ranges
* Ref: https://www.elastic.co/guide/en/security/current/lists-api-import-list-items.html
*/
export const importValueList = (
export const uploadListItemData = (
file: string,
type: string
type: string,
data: string
): Cypress.Chainable<Cypress.Response> => {
return cy.fixture(file).then((data) => {
return cy.request({
method: 'POST',
url: `api/lists/items/_import?type=${type}`,
encoding: 'binary',
headers: {
'kbn-xsrf': 'upload-value-lists',
'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryJLrRH89J8QVArZyv',
},
body: `------WebKitFormBoundaryJLrRH89J8QVArZyv\nContent-Disposition: form-data; name="file"; filename="${file}"\n\n${data}`,
});
const removedEmptyLines = data
.split('\n')
.filter((line) => line.trim() !== '')
.join('\n');

return cy.request({
method: 'POST',
url: `api/lists/items/_import?type=${type}`,
encoding: 'binary',
headers: {
'kbn-xsrf': 'upload-value-lists',
'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryJLrRH89J8QVArZyv',
},
body: `------WebKitFormBoundaryJLrRH89J8QVArZyv\nContent-Disposition: form-data; name="file"; filename="${file}"\n\n${removedEmptyLines}`,
});
};

/**
* Checks a single value list file against a data set to ensure it has been uploaded.
*
* You can optionally pass in an array of test suggestions which will be useful for if you are
* using a range such as a CIDR range and need to ensure that test range has been added to the
* list but you cannot run an explicit test against that range.
*
* This also will remove any upload data such as empty strings that can happen from the fixture
* due to extra lines being added from formatters.
* @param file The file that was imported
* @param data The contents to check unless testSuggestions is given.
* @param type The type of the file import such as ip/keyword/text etc...
* @param testSuggestions The type of test to use rather than the fixture file which is useful for ranges
* Ref: https://www.elastic.co/guide/en/security/current/lists-api-import-list-items.html
*/
export const checkListItemData = (
file: string,
data: string,
testSuggestions: string[] | undefined
): Cypress.Chainable<JQuery<HTMLElement>> => {
const importCheckLines =
testSuggestions == null
? data.split('\n').filter((line) => line.trim() !== '')
: testSuggestions;

return cy.wrap(importCheckLines).each((line) => {
return cy
.request({
retryOnStatusCodeFailure: true,
method: 'GET',
url: `api/lists/items?list_id=${file}&value=${line}`,
})
.then((resp) => {
expect(resp.status).to.eq(200);
});
});
};

/**
* Imports a single value list file this using Cypress Request and lists REST API. After it
* imports the data, it will re-check and ensure that the data is there before continuing to
* get us more deterministic.
*
* You can optionally pass in an array of test suggestions which will be useful for if you are
* using a range such as a CIDR range and need to ensure that test range has been added to the
* list but you cannot run an explicit test against that range.
*
* This also will remove any upload data such as empty strings that can happen from the fixture
* due to extra lines being added from formatters.
* @param file The file to import
* @param type The type of the file import such as ip/keyword/text etc...
* @param testSuggestions The type of test to use rather than the fixture file which is useful for ranges
* Ref: https://www.elastic.co/guide/en/security/current/lists-api-import-list-items.html
*/
export const importValueList = (
file: string,
type: string,
testSuggestions: string[] | undefined = undefined
): Cypress.Chainable<JQuery<HTMLElement>> => {
return cy
.fixture<string>(file)
.then((data) => uploadListItemData(file, type, data))
.fixture<string>(file)
.then((data) => checkListItemData(file, data, testSuggestions));
};

/**
* If you are on the value lists from the UI, this will loop over all the HTML elements
* that have action-delete-value-list-${list_name} and delete all of those value lists
Expand Down

0 comments on commit 24c7b2d

Please sign in to comment.