Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Search] Inference Management FTR Tests #188438

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .buildkite/ftr_configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ enabled:
- x-pack/test/functional/apps/saved_query_management/config.ts
- x-pack/test/functional/apps/security/config.ts
- x-pack/test/functional/apps/slo/embeddables/config.ts
- x-pack/test/functional/apps/search_inference_management/config.ts
- x-pack/test/functional/apps/search_playground/config.ts
- x-pack/test/functional/apps/snapshot_restore/config.ts
- x-pack/test/functional/apps/spaces/config.ts
Expand Down
14 changes: 7 additions & 7 deletions config/serverless.es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ xpack.osquery.enabled: false
## Fine-tune the search solution feature privileges. Also, refer to `serverless.yml` for the project-agnostic overrides.
xpack.features.overrides:
### Dashboards feature is moved from Analytics category to the Search one.
dashboard.category: "enterpriseSearch"
dashboard.category: 'enterpriseSearch'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need these quote changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not need these quote changes. These go added when I rand lint command so I assumed something changed with the eslint configuration which forced the file to update.

### Dev Tools feature is moved from Analytics category to the Search one.
dev_tools.category: "enterpriseSearch"
dev_tools.category: 'enterpriseSearch'
### Discover feature is moved from Analytics category to the Search one.
discover.category: "enterpriseSearch"
discover.category: 'enterpriseSearch'
### Machine Learning feature is moved from Analytics category to the Management one.
ml.category: "management"
ml.category: 'management'
### Stack Alerts feature is moved from Analytics category to the Search one renamed to simply `Alerts`.
stackAlerts:
name: "Alerts"
category: "enterpriseSearch"
name: 'Alerts'
category: 'enterpriseSearch'

## Cloud settings
xpack.cloud.serverless.project_type: search
Expand Down Expand Up @@ -65,7 +65,7 @@ data_visualizer.resultLinks.fileBeat.enabled: false
xpack.searchPlayground.ui.enabled: true

# Search InferenceEndpoints
xpack.searchInferenceEndpoints.ui.enabled: false
xpack.searchInferenceEndpoints.ui.enabled: true
Copy link
Contributor

@saikatsarkar056 saikatsarkar056 Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the recommendation #5, we may need to hide the Inference Endpoints page in the servereless environment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, we will not be merging this PR as the requirements changed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Samiul-TheSoccerFan we can merge this PR, we just need to not enable the FF. instead run the new FTRs in the feature flag config and only enable it there.


# Search Notebooks
xpack.search.notebooks.catalog.url: https://elastic-enterprise-search.s3.us-east-2.amazonaws.com/serverless/catalog.json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const EndpointsTable: React.FC<EndpointsTableProps> = ({
onChange={onChange}
pagination={pagination}
sorting={sorting}
data-test-subj="inferenceEndpointTable"
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ interface UseFilterParams {
options: MultiSelectFilterOption[];
renderOption?: (option: MultiSelectFilterOption) => React.ReactNode;
selectedOptionKeys?: string[];
dataTestSubj: string;
}

export const MultiSelectFilter: React.FC<UseFilterParams> = ({
Expand All @@ -40,6 +41,7 @@ export const MultiSelectFilter: React.FC<UseFilterParams> = ({
options: rawOptions,
selectedOptionKeys = [],
renderOption,
dataTestSubj,
}) => {
const { euiTheme } = useEuiTheme();
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
Expand All @@ -51,7 +53,7 @@ export const MultiSelectFilter: React.FC<UseFilterParams> = ({
}));

return (
<EuiFilterGroup>
<EuiFilterGroup data-test-subj={dataTestSubj}>
<EuiPopover
ownFocus
button={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const ServiceProviderFilter: React.FC<Props> = ({ optionKeys, onChange })
options={options}
renderOption={(option) => option.label}
selectedOptionKeys={optionKeys}
dataTestSubj="inferenceServiceField"
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const TaskTypeFilter: React.FC<Props> = ({ optionKeys, onChange }) => {
options={options}
renderOption={(option) => option.label}
selectedOptionKeys={optionKeys}
dataTestSubj="inferenceTypeField"
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export const useDeleteAction = ({ onActionSuccess }: UseActionProps) => {
key="delete"
icon={<EuiIcon type="trash" size="m" color={'danger'} />}
onClick={() => openModal(selectedEndpoint)}
data-test-subj="inference-endpoints-action-delete-endpoint"
>
{i18n.DELETE_ACTION_LABEL}
</EuiContextMenuItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const ActionColumn: React.FC<{ interfaceEndpoint: InferenceEndpointUI }>
aria-label={'Actions'}
color="text"
disabled={false}
data-test-subj="inference-tableRow-action-button"
/>
}
isOpen={isPopoverOpen}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const useTableColumns = () => {
{
field: 'deployment',
name: '',
'data-test-subj': 'deploymentCell',
render: (deployment: DeploymentStatusEnum) => {
if (deployment != null) {
return <DeploymentStatus status={deployment} />;
Expand All @@ -37,6 +38,7 @@ export const useTableColumns = () => {
{
field: 'endpoint',
name: i18n.ENDPOINT,
'data-test-subj': 'endpointCell',
render: (endpoint: InferenceAPIConfigResponse) => {
if (endpoint != null) {
return <EndpointInfo endpoint={endpoint} />;
Expand All @@ -49,6 +51,7 @@ export const useTableColumns = () => {
{
field: 'provider',
name: i18n.SERVICE_PROVIDER,
'data-test-subj': 'providerCell',
render: (provider: ServiceProviderKeys) => {
if (provider != null) {
return <ServiceProvider providerKey={provider} />;
Expand All @@ -62,6 +65,7 @@ export const useTableColumns = () => {
{
field: 'type',
name: i18n.TASK_TYPE,
'data-test-subj': 'typeCell',
render: (type: TaskTypes) => {
if (type != null) {
return <TaskType type={type} />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const TableSearch: React.FC<TableSearchComponentProps> = ({ searchKey, se
onChange={(e) => setSearchKey(e.target.value)}
onSearch={onSearch}
value={searchKey}
data-test-subj="inferenceSearchField"
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const AddEmptyPrompt: React.FC<AddEmptyPromptProps> = ({ setIsInferenceFl
color="plain"
hasShadow
icon={<EuiImage size="fullWidth" src={inferenceEndpoint} alt="" />}
title={<h2>{i18n.INFERENCE_ENDPOINT_LABEL}</h2>}
title={<h2 data-test-subj="allInferenceEndpointsPage">{i18n.INFERENCE_ENDPOINT_LABEL}</h2>}
body={
<EuiFlexGroup direction="column">
<EuiFlexItem data-test-subj="createFirstInferenceEndpointDescription">
Expand Down Expand Up @@ -73,6 +73,7 @@ export const AddEmptyPrompt: React.FC<AddEmptyPromptProps> = ({ setIsInferenceFl
<EuiButton
iconType="plusInCircle"
onClick={() => setIsInferenceFlyoutVisible(true)}
data-test-subj="createFirstElserInferenceEndpointDescription"
>
{i18n.ADD_ENDPOINT_LABEL}
</EuiButton>
Expand All @@ -88,6 +89,7 @@ export const AddEmptyPrompt: React.FC<AddEmptyPromptProps> = ({ setIsInferenceFl
<EuiButton
iconType="plusInCircle"
onClick={() => setIsInferenceFlyoutVisible(true)}
data-test-subj="createFirstE5InferenceEndpointDescription"
>
{i18n.ADD_ENDPOINT_LABEL}
</EuiButton>
Expand Down
17 changes: 17 additions & 0 deletions x-pack/test/functional/apps/search_inference_management/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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 { FtrConfigProviderContext } from '@kbn/test';

export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const functionalConfig = await readConfigFile(require.resolve('../../config.base.js'));

return {
...functionalConfig.getAll(),
testFiles: [require.resolve('.')],
};
}
13 changes: 13 additions & 0 deletions x-pack/test/functional/apps/search_inference_management/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* 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 { FtrProviderContext } from '../../ftr_provider_context';

export default function ({ loadTestFile }: FtrProviderContext) {
describe('inference management', async () => {
loadTestFile(require.resolve('./inference_management.ess.ts'));
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* 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 { ModelConfig } from '@kbn/inference_integration_flyout/types';

import { FtrProviderContext } from '../../ftr_provider_context';

export default function ({ getPageObjects, getService }: FtrProviderContext) {
const pageObjects = getPageObjects(['common', 'inferenceManagement']);
const browser = getService('browser');
const ml = getService('ml');

/* Due to a race condition between registrating an app and license subscription,
the FTR tests can not access the desired application.
*/
describe.skip('ESS Inference Management UI', function () {
this.tags('skipMKI');

before(async () => {
await pageObjects.common.navigateToApp('home');
await pageObjects.common.navigateToApp('enterprise_search/overview');
await pageObjects.common.navigateToApp('inferenceManagement');
});

describe.skip('endpoint empty view', () => {
it('is loaded successfully', async () => {
await pageObjects.inferenceManagement.InferenceEmptyPage.expectComponentsToBeExist();
});
it('opens add inference flyout', async () => {
await pageObjects.inferenceManagement.InferenceEmptyPage.expectFlyoutTobeOpened();
});
});

describe.skip('endpoint tabular view', () => {
before(async () => {
const modelConfig: ModelConfig = {
service: 'elser',
service_settings: {
num_allocations: 1,
num_threads: 1,
},
};
await ml.api.createInferenceEndpoint('endpoint-1', 'sparse_embedding', modelConfig);
Copy link
Contributor

@saikatsarkar056 saikatsarkar056 Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This endpoint was created in the ‘before’ block. We may need to write some cleanup code in the ‘after’ block to delete the endpoint and remove the underlying trained model if it was added during the creation of the endpoint.

I’m suggesting this because we previously had a CI/CD failure due to not cleaning up created resources. See this PR as an example of cleanup.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the last test, we removed the inference endpoint from the UI. Do we still need to do the cleanup or it will be handled through the application itself?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check whether creation of inference endpoint adds any new trained model. If so, we need to clean up the trained model.

await browser.refresh();
});

it('is loaded successfully', async () => {
await pageObjects.inferenceManagement.InferenceTabularPage.expectHeaderToBeExist();
await pageObjects.inferenceManagement.InferenceTabularPage.expectTabularViewToBeLoaded();
});

it('can copy an endpoint id', async () => {
await pageObjects.inferenceManagement.InferenceTabularPage.expectToCopyEndpoint();
});

it('can delete an endpoint', async () => {
await pageObjects.inferenceManagement.InferenceTabularPage.expectEndPointTobeDeleted();
});
});
});
}
3 changes: 3 additions & 0 deletions x-pack/test/functional/config.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ export default async function ({ readConfigFile }) {
maintenanceWindows: {
pathname: '/app/management/insightsAndAlerting/maintenanceWindows',
},
inferenceManagement: {
pathname: '/app/enterprise_search/relevance/inference_endpoints',
},
},

suiteTags: {
Expand Down
2 changes: 2 additions & 0 deletions x-pack/test/functional/page_objects/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { GraphPageObject } from './graph_page';
import { GrokDebuggerPageObject } from './grok_debugger_page';
import { IndexLifecycleManagementPageProvider } from './index_lifecycle_management_page';
import { IndexManagementPageProvider } from './index_management_page';
import { InferenceManagementPageProvider } from './inference_management_page';
import { InfraHomePageProvider } from './infra_home_page';
import { InfraHostsViewProvider } from './infra_hosts_view';
import { InfraLogsPageProvider } from './infra_logs_page';
Expand Down Expand Up @@ -73,6 +74,7 @@ export const pageObjects = {
grokDebugger: GrokDebuggerPageObject,
indexLifecycleManagement: IndexLifecycleManagementPageProvider,
indexManagement: IndexManagementPageProvider,
inferenceManagement: InferenceManagementPageProvider,
infraHome: InfraHomePageProvider,
infraHostsView: InfraHostsViewProvider,
infraLogs: InfraLogsPageProvider,
Expand Down
82 changes: 82 additions & 0 deletions x-pack/test/functional/page_objects/inference_management_page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* 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 expect from '@kbn/expect';
import { FtrProviderContext } from '../ftr_provider_context';

export function InferenceManagementPageProvider({ getService }: FtrProviderContext) {
const testSubjects = getService('testSubjects');
const browser = getService('browser');

return {
InferenceEmptyPage: {
async expectComponentsToBeExist() {
const endpointDesc = await testSubjects.find('createFirstInferenceEndpointDescription');
const endpointDescMsg = await endpointDesc.getVisibleText();
expect(endpointDescMsg).to.contain(
'Connect to your third-party model provider to create an inference endpoint for semantic search.'
);
await testSubjects.existOrFail('addEndpointButtonForEmptyPrompt');
await testSubjects.existOrFail('createFirstElserInferenceEndpointDescription');
await testSubjects.existOrFail('createFirstE5InferenceEndpointDescription');
},

async expectFlyoutTobeOpened() {
await testSubjects.click('addEndpointButtonForEmptyPrompt');
await testSubjects.existOrFail('addInferenceEndpoint');
await testSubjects.click('euiFlyoutCloseButton');
},
},
InferenceTabularPage: {
async expectHeaderToBeExist() {
await testSubjects.existOrFail('allInferenceEndpointsPage');
await testSubjects.existOrFail('addEndpointButtonForAllInferenceEndpoints');
expect(await testSubjects.isEnabled('addEndpointButtonForAllInferenceEndpoints')).to.be(
true
);
},

async expectTabularViewToBeLoaded() {
await testSubjects.existOrFail('inferenceSearchField');
await testSubjects.existOrFail('inferenceTypeField');
await testSubjects.existOrFail('inferenceServiceField');

const table = await testSubjects.find('inferenceEndpointTable');
const rows = await table.findAllByClassName('euiTableRow');
expect(rows.length).to.equal(1);

await testSubjects.existOrFail('deploymentCell');

const endpointCell = await testSubjects.find('endpointCell');
const endpointName = await endpointCell.getVisibleText();
expect(endpointName).to.contain('endpoint-1');

const providerCell = await testSubjects.find('providerCell');
const providerName = await providerCell.getVisibleText();
expect(providerName).to.equal('ELSER');

const typeCell = await testSubjects.find('typeCell');
const typeName = await typeCell.getVisibleText();
expect(typeName).to.equal('sparse_embedding');
},

async expectEndPointTobeDeleted() {
await testSubjects.click('inference-tableRow-action-button');
await testSubjects.click('inference-endpoints-action-delete-endpoint');
await testSubjects.click('confirmModalConfirmButton');
await testSubjects.missingOrFail('inferenceEndpointTable');
},

async expectToCopyEndpoint() {
await testSubjects.click('inference-tableRow-action-button');
await testSubjects.click('inference-endpoints-action-copy-id-label');

expect((await browser.getClipboardValue()).includes('endpoint-1')).to.be(true);
},
},
};
}
3 changes: 2 additions & 1 deletion x-pack/test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@
"@kbn/ml-trained-models-utils",
"@kbn/openapi-common",
"@kbn/securitysolution-lists-common",
"@kbn/securitysolution-exceptions-common"
"@kbn/securitysolution-exceptions-common",
"@kbn/inference_integration_flyout"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {

loadTestFile(require.resolve('./ml'));
loadTestFile(require.resolve('./search_homepage'));
loadTestFile(require.resolve('./inference_management'));
});
}
Loading