Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ const appServices = {
api: apiService,
notifications: notificationServiceMock.createSetupContract(),
history,
urlGenerators: {
getUrlGenerator: jest.fn().mockReturnValue({
createUrl: jest.fn(),
}),
},
};

export const setupEnvironment = () => {
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/ingest_pipelines/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "8.0.0",
"server": true,
"ui": true,
"requiredPlugins": ["licensing", "management", "features"],
"requiredPlugins": ["licensing", "management", "features", "share"],
"optionalPlugins": ["security", "usageCollection"],
"configPath": ["xpack", "ingest_pipelines"],
"requiredBundles": ["esUiShared", "kibanaReact"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,20 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
]);
};

const setFetchDocumentsResponse = (response?: HttpResponse, error?: any) => {
const status = error ? error.status || 400 : 200;
const body = error ? JSON.stringify(error.body) : JSON.stringify(response);

server.respondWith('GET', '/api/ingest_pipelines/documents/:index/:id', [
status,
{ 'Content-Type': 'application/json' },
body,
]);
};

return {
setSimulatePipelineResponse,
setFetchDocumentsResponse,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ const appServices = {
notifications: notificationServiceMock.createSetupContract(),
history,
uiSettings: {},
urlGenerators: {
getUrlGenerator: jest.fn().mockReturnValue({
createUrl: jest.fn(),
}),
},
};

const testBedSetup = registerTestBed<TestSubject>(
Expand Down Expand Up @@ -180,6 +185,20 @@ const createActions = (testBed: TestBed<TestSubject>) => {
});
component.update();
},

async toggleDocumentsAccordion() {
await act(async () => {
find('importDocumentsAccordion').simulate('click');
});
component.update();
},

async clickImportButton() {
await act(async () => {
find('importDocumentButton').simulate('click');
});
component.update();
},
};
};

Expand Down Expand Up @@ -229,4 +248,7 @@ type TestSubject =
| 'configurationTab'
| 'outputTab'
| 'processorOutputTabContent'
| 'importDocumentsAccordion'
| 'importDocumentButton'
| 'importDocumentError'
| string;
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,9 @@ describe('Test pipeline', () => {
const { actions, find, exists } = testBed;

const error = {
status: 400,
error: 'Bad Request',
message:
'"[parse_exception] [_source] required property is missing, with { property_name="_source" }"',
status: 500,
error: 'Internal server error',
message: 'Internal server error',
};

httpRequestsMockHelpers.setSimulatePipelineResponse(undefined, { body: error });
Expand All @@ -153,13 +152,87 @@ describe('Test pipeline', () => {
actions.clickAddDocumentsButton();

// Add invalid sample documents array and run the pipeline
actions.addDocumentsJson(JSON.stringify([{}]));
actions.addDocumentsJson(
JSON.stringify([
{
_index: 'test',
_id: '1',
_version: 1,
_seq_no: 0,
_primary_term: 1,
_source: {
name: 'John Doe',
},
},
])
);
await actions.clickRunPipelineButton();

// Verify error rendered
expect(exists('pipelineExecutionError')).toBe(true);
expect(find('pipelineExecutionError').text()).toContain(error.message);
});

describe('Import indexed documents', () => {
test('should successfully import an index document', async () => {
const { actions, form } = testBed;

const { _index: index, _id: documentId } = DOCUMENTS[0];

httpRequestsMockHelpers.setFetchDocumentsResponse(DOCUMENTS[0]);

// Open flyout
actions.clickAddDocumentsButton();

// Open documents accordion, click run without required fields, and verify error messages
await actions.toggleDocumentsAccordion();
await actions.clickImportButton();
expect(form.getErrorsMessages()).toEqual([
'An index name is required.',
'A document ID is required.',
]);

// Add required fields, and click run
form.setInputValue('indexField.input', index);
form.setInputValue('idField.input', documentId);
await actions.clickImportButton();

// Verify request
const latestRequest = server.requests[server.requests.length - 1];
expect(latestRequest.status).toEqual(200);
expect(latestRequest.url).toEqual(`/api/ingest_pipelines/documents/${index}/${documentId}`);
});

test('should surface API errors from the request', async () => {
const { actions, form, exists, find } = testBed;

const nonExistentDoc = {
index: 'foo',
id: '1',
};

const error = {
status: 404,
error: 'Not found',
message: '[index_not_found_exception] no such index',
};

httpRequestsMockHelpers.setFetchDocumentsResponse(undefined, { body: error });

// Open flyout
actions.clickAddDocumentsButton();

// Open documents accordion, add required fields, and click run
await actions.toggleDocumentsAccordion();
form.setInputValue('indexField.input', nonExistentDoc.index);
form.setInputValue('idField.input', nonExistentDoc.id);
await actions.clickImportButton();

// Verify error rendered
expect(exists('importDocumentError')).toBe(true);
expect(find('importDocumentError').text()).toContain(error.message);
});
});
});

describe('Processors', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
EuiCallOut,
} from '@elastic/eui';

import { Form, FormHook } from '../../../../../shared_imports';
import { FormHook } from '../../../../../shared_imports';
import { Document } from '../../types';

import { Tabs, TestPipelineFlyoutTab, OutputTab, DocumentsTab } from './test_pipeline_flyout_tabs';
Expand Down Expand Up @@ -71,19 +71,11 @@ export const TestPipelineFlyout: React.FunctionComponent<Props> = ({
} else {
// default to "Documents" tab
tabContent = (
<Form
<DocumentsTab
form={form}
data-test-subj="testPipelineForm"
isInvalid={form.isSubmitted && !form.isValid}
onSubmit={validateAndTestPipeline}
error={form.getErrors()}
>
<DocumentsTab
validateAndTestPipeline={validateAndTestPipeline}
isRunningTest={isRunningTest}
isSubmitButtonDisabled={form.isSubmitted && !form.isValid}
/>
</Form>
validateAndTestPipeline={validateAndTestPipeline}
isRunningTest={isRunningTest}
/>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,30 @@ export const documentsSchema: FormSchema = {
}
},
},
{
validator: ({ value }: ValidationFuncArg<any, any>) => {
const parsedJSON = JSON.parse(value);

const isMissingSourceField = parsedJSON.find((obj: { _source?: object }) => {
if (!obj._source) {
return true;
}

return false;
});

if (isMissingSourceField) {
return {
message: i18n.translate(
'xpack.ingestPipelines.testPipelineFlyout.documentsForm.sourceFieldRequiredError',
{
defaultMessage: 'Documents require a _source field.',
}
),
};
}
},
},
],
},
};
Loading