mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[ML] Add functional tests for reauthorizing transforms (#156699)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
8e2b5ae796
commit
3766cd66ab
15 changed files with 282 additions and 15 deletions
|
@ -225,7 +225,7 @@ enabled:
|
|||
- x-pack/test/functional_basic/apps/ml/data_visualizer/group2/config.ts
|
||||
- x-pack/test/functional_basic/apps/ml/data_visualizer/group3/config.ts
|
||||
- x-pack/test/functional_basic/apps/transform/creation/index_pattern/config.ts
|
||||
- x-pack/test/functional_basic/apps/transform/start_reset_delete/config.ts
|
||||
- x-pack/test/functional_basic/apps/transform/actions/config.ts
|
||||
- x-pack/test/functional_basic/apps/transform/edit_clone/config.ts
|
||||
- x-pack/test/functional_basic/apps/transform/creation/runtime_mappings_saved_search/config.ts
|
||||
- x-pack/test/functional_basic/apps/transform/permissions/config.ts
|
||||
|
@ -291,7 +291,7 @@ enabled:
|
|||
- x-pack/test/functional/apps/status_page/config.ts
|
||||
- x-pack/test/functional/apps/transform/creation/index_pattern/config.ts
|
||||
- x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/config.ts
|
||||
- x-pack/test/functional/apps/transform/start_reset_delete/config.ts
|
||||
- x-pack/test/functional/apps/transform/actions/config.ts
|
||||
- x-pack/test/functional/apps/transform/edit_clone/config.ts
|
||||
- x-pack/test/functional/apps/transform/permissions/config.ts
|
||||
- x-pack/test/functional/apps/transform/feature_controls/config.ts
|
||||
|
|
|
@ -114,6 +114,7 @@ export const TransformManagement: FC = () => {
|
|||
<EuiCallOut
|
||||
iconType="alert"
|
||||
color="warning"
|
||||
data-test-subj="transformPageReauthorizeCallout"
|
||||
title={`${insufficientPermissionsMsg} ${actionMsg}`}
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
|
|
|
@ -122,7 +122,7 @@ With PATH_TO_CONFIG and other options as follows.
|
|||
edit, clone | `test/functional/apps/transform/edit_clone/config.ts`
|
||||
feature controls | `test/functional/apps/transform/feature_controls/config.ts`
|
||||
permissions | `test/functional/apps/transform/permissions/config.ts`
|
||||
start, reset, delete | `test/functional/apps/transform/start_reset_delete/config.ts`
|
||||
actions | `test/functional/apps/transform/actions/config.ts`
|
||||
|
||||
1. Functional UI tests with `Basic` license:
|
||||
|
||||
|
@ -133,7 +133,7 @@ With PATH_TO_CONFIG and other options as follows.
|
|||
edit, clone | `test/functional_basic/apps/transform/edit_clone/config.ts`
|
||||
feature controls | `test/functional_basic/apps/transform/feature_controls/config.ts`
|
||||
permissions | `test/functional_basic/apps/transform/permissions/config.ts`
|
||||
start, reset, delete | `test/functional_basic/apps/transform/start_reset_delete/config.ts`
|
||||
actions | `test/functional_basic/apps/transform/actions/config.ts`
|
||||
|
||||
1. API integration tests with `Trial` license:
|
||||
|
||||
|
|
|
@ -21,9 +21,6 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
const supertest = getService('supertestWithoutAuth');
|
||||
const transform = getService('transform');
|
||||
|
||||
// If transform was created with sufficient -> should still authorize and start
|
||||
// If transform was created with insufficient -> should still authorize and start
|
||||
|
||||
function getTransformIdByUser(username: USER) {
|
||||
return `transform-by-${username}`;
|
||||
}
|
||||
|
@ -51,6 +48,8 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
await transform.api.deleteIndices(destinationIndex);
|
||||
}
|
||||
|
||||
// If transform was created with sufficient permissions -> should create and start
|
||||
// If transform was created with insufficient permissions -> should create but not start
|
||||
describe('/api/transform/reauthorize_transforms', function () {
|
||||
const apiKeysForTransformUsers = new Map<USER, SecurityCreateApiKeyResponse>();
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
...functionalConfig.getAll(),
|
||||
testFiles: [require.resolve('.')],
|
||||
junit: {
|
||||
reportName: 'Chrome X-Pack UI Functional Tests - transform - start reset & delete',
|
||||
reportName: 'Chrome X-Pack UI Functional Tests - transform - actions',
|
||||
},
|
||||
};
|
||||
}
|
|
@ -11,7 +11,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) {
|
|||
const esArchiver = getService('esArchiver');
|
||||
const transform = getService('transform');
|
||||
|
||||
describe('transform - start reset & delete', function () {
|
||||
describe('transform - actions', function () {
|
||||
this.tags('transform');
|
||||
|
||||
before(async () => {
|
||||
|
@ -33,6 +33,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
loadTestFile(require.resolve('./deleting'));
|
||||
loadTestFile(require.resolve('./reauthorizing'));
|
||||
loadTestFile(require.resolve('./resetting'));
|
||||
loadTestFile(require.resolve('./starting'));
|
||||
});
|
221
x-pack/test/functional/apps/transform/actions/reauthorizing.ts
Normal file
221
x-pack/test/functional/apps/transform/actions/reauthorizing.ts
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* 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 { TRANSFORM_HEALTH_LABEL, TRANSFORM_STATE } from '@kbn/transform-plugin/common/constants';
|
||||
import type {
|
||||
TransformLatestConfig,
|
||||
TransformPivotConfig,
|
||||
} from '@kbn/transform-plugin/common/types/transform';
|
||||
import type { SecurityCreateApiKeyResponse } from '@elastic/elasticsearch/lib/api/types';
|
||||
import type { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
import { getLatestTransformConfig, getPivotTransformConfig } from '../helpers';
|
||||
import { USER } from '../../../services/transform/security_common';
|
||||
import { COMMON_REQUEST_HEADERS } from '../../../services/ml/common_api';
|
||||
|
||||
interface TestDataPivot {
|
||||
suiteTitle: string;
|
||||
originalConfig: TransformPivotConfig;
|
||||
mode: 'batch' | 'continuous';
|
||||
type: 'pivot';
|
||||
expected: {
|
||||
originalState: object;
|
||||
reauthorizeEnabled: boolean;
|
||||
reauthorizedState: object;
|
||||
};
|
||||
created_by_user: USER;
|
||||
current_user: USER;
|
||||
}
|
||||
|
||||
interface TestDataLatest {
|
||||
suiteTitle: string;
|
||||
originalConfig: TransformLatestConfig;
|
||||
mode: 'batch' | 'continuous';
|
||||
type: 'latest';
|
||||
expected: {
|
||||
originalState: object;
|
||||
reauthorizeEnabled: boolean;
|
||||
reauthorizedState: object;
|
||||
};
|
||||
created_by_user: USER;
|
||||
current_user: USER;
|
||||
}
|
||||
|
||||
type TestData = TestDataPivot | TestDataLatest;
|
||||
|
||||
function generateHeaders(apiKey: SecurityCreateApiKeyResponse) {
|
||||
return {
|
||||
...COMMON_REQUEST_HEADERS,
|
||||
'es-secondary-authorization': `ApiKey ${apiKey.encoded}`,
|
||||
};
|
||||
}
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const transform = getService('transform');
|
||||
|
||||
const apiKeysForTransformUsers = new Map<USER, SecurityCreateApiKeyResponse>();
|
||||
|
||||
describe('reauthorizing', function () {
|
||||
const PREFIX = 'reauthorizing';
|
||||
const testDataList: TestData[] = [
|
||||
{
|
||||
suiteTitle: 'continuous pivot transform (created by viewer, viewed by viewer)',
|
||||
originalConfig: getPivotTransformConfig(`${PREFIX}-${USER.TRANSFORM_VIEWER}-1`, true),
|
||||
mode: 'continuous',
|
||||
type: 'pivot',
|
||||
expected: {
|
||||
originalState: { status: TRANSFORM_STATE.STOPPED, health: TRANSFORM_HEALTH_LABEL.red },
|
||||
reauthorizeEnabled: false,
|
||||
reauthorizedState: {
|
||||
status: TRANSFORM_STATE.STARTED,
|
||||
health: TRANSFORM_HEALTH_LABEL.green,
|
||||
},
|
||||
},
|
||||
created_by_user: USER.TRANSFORM_VIEWER,
|
||||
current_user: USER.TRANSFORM_VIEWER,
|
||||
},
|
||||
{
|
||||
suiteTitle: 'batch pivot transform (created by viewer, viewed by poweruser)',
|
||||
originalConfig: getPivotTransformConfig(PREFIX, false),
|
||||
mode: 'batch',
|
||||
type: 'pivot',
|
||||
expected: {
|
||||
originalState: { status: TRANSFORM_STATE.STOPPED, health: TRANSFORM_HEALTH_LABEL.red },
|
||||
reauthorizeEnabled: true,
|
||||
reauthorizedState: {
|
||||
status: TRANSFORM_STATE.STOPPED,
|
||||
progress: '100',
|
||||
health: TRANSFORM_HEALTH_LABEL.green,
|
||||
},
|
||||
},
|
||||
created_by_user: USER.TRANSFORM_VIEWER,
|
||||
current_user: USER.TRANSFORM_POWERUSER,
|
||||
},
|
||||
{
|
||||
suiteTitle: 'continuous pivot transform (created by viewer, authorized by poweruser)',
|
||||
originalConfig: getPivotTransformConfig(`${PREFIX}-${USER.TRANSFORM_VIEWER}-2`, true),
|
||||
mode: 'continuous',
|
||||
type: 'pivot',
|
||||
expected: {
|
||||
originalState: { status: TRANSFORM_STATE.STOPPED, health: TRANSFORM_HEALTH_LABEL.red },
|
||||
reauthorizeEnabled: true,
|
||||
reauthorizedState: {
|
||||
status: TRANSFORM_STATE.STARTED,
|
||||
health: TRANSFORM_HEALTH_LABEL.green,
|
||||
},
|
||||
},
|
||||
created_by_user: USER.TRANSFORM_VIEWER,
|
||||
current_user: USER.TRANSFORM_POWERUSER,
|
||||
},
|
||||
{
|
||||
suiteTitle: 'continuous latest transform (created by poweruser, viewed by viewer)',
|
||||
originalConfig: getLatestTransformConfig(`${PREFIX}-${USER.TRANSFORM_POWERUSER}-1`, true),
|
||||
mode: 'continuous',
|
||||
type: 'latest',
|
||||
expected: {
|
||||
originalState: { status: TRANSFORM_STATE.STARTED, health: TRANSFORM_HEALTH_LABEL.green },
|
||||
reauthorizeEnabled: false,
|
||||
reauthorizedState: {
|
||||
status: TRANSFORM_STATE.STARTED,
|
||||
health: TRANSFORM_HEALTH_LABEL.green,
|
||||
},
|
||||
},
|
||||
created_by_user: USER.TRANSFORM_POWERUSER,
|
||||
current_user: USER.TRANSFORM_VIEWER,
|
||||
},
|
||||
];
|
||||
|
||||
before(async () => {
|
||||
const apiKeyForTransformUsers =
|
||||
await transform.securityCommon.createApiKeyForTransformUsers();
|
||||
|
||||
apiKeyForTransformUsers.forEach(({ user, apiKey }) =>
|
||||
apiKeysForTransformUsers.set(user.name as USER, apiKey)
|
||||
);
|
||||
|
||||
await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce');
|
||||
await transform.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date');
|
||||
|
||||
for (const testData of testDataList) {
|
||||
await transform.api.createTransform(testData.originalConfig.id, testData.originalConfig, {
|
||||
deferValidation: true,
|
||||
// Create transforms with secondary authorization headers
|
||||
headers: generateHeaders(apiKeysForTransformUsers.get(testData.created_by_user)!),
|
||||
});
|
||||
// For transforms created with insufficient permissions, they can be created but not started
|
||||
// so we should not assert that the api call is successful here
|
||||
await transform.api.startTransform(testData.originalConfig.id, false);
|
||||
}
|
||||
await transform.testResources.setKibanaTimeZoneToUTC();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await transform.securityCommon.clearAllTransformApiKeys();
|
||||
|
||||
for (const testData of testDataList) {
|
||||
await transform.testResources.deleteIndexPatternByTitle(testData.originalConfig.dest.index);
|
||||
await transform.api.deleteIndices(testData.originalConfig.dest.index);
|
||||
}
|
||||
|
||||
await transform.api.cleanTransformIndices();
|
||||
await transform.testResources.deleteIndexPatternByTitle('ft_ecommerce');
|
||||
});
|
||||
|
||||
for (const testData of testDataList) {
|
||||
const transformId = testData.originalConfig.id;
|
||||
|
||||
describe(`${testData.suiteTitle}`, function () {
|
||||
it('reauthorize transform', async () => {
|
||||
await transform.securityUI.loginAs(testData.current_user);
|
||||
|
||||
await transform.testExecution.logTestStep('should load the home page');
|
||||
await transform.navigation.navigateTo();
|
||||
await transform.management.assertTransformListPageExists();
|
||||
|
||||
await transform.testExecution.logTestStep('should display the transforms table');
|
||||
await transform.management.assertTransformsTableExists();
|
||||
|
||||
await transform.testExecution.logTestStep(
|
||||
'should display the transforms reauthorize callout'
|
||||
);
|
||||
await transform.management.assertTransformsReauthorizeCalloutExists();
|
||||
|
||||
await transform.testExecution.logTestStep(
|
||||
'should display the original transform in the transform list'
|
||||
);
|
||||
await transform.table.filterWithSearchString(transformId, 1);
|
||||
await transform.table.assertTransformRowFields(
|
||||
transformId,
|
||||
testData.expected.originalState
|
||||
);
|
||||
|
||||
if (testData.expected.reauthorizeEnabled) {
|
||||
await transform.testExecution.logTestStep('should reauthorize the transform');
|
||||
await transform.table.assertTransformRowActionEnabled(
|
||||
transformId,
|
||||
'Reauthorize',
|
||||
testData.expected.reauthorizeEnabled
|
||||
);
|
||||
await transform.table.clickTransformRowAction(transformId, 'Reauthorize');
|
||||
await transform.table.confirmReauthorizeTransform();
|
||||
|
||||
await transform.table.assertTransformRowFields(
|
||||
transformId,
|
||||
testData.expected.reauthorizedState
|
||||
);
|
||||
await transform.testExecution.logTestStep('should not show Reauthorize action anymore');
|
||||
await transform.table.assertTransformRowActionMissing(transformId, 'Reauthorize');
|
||||
} else {
|
||||
await transform.testExecution.logTestStep('should show disabled action menu button');
|
||||
await transform.table.assertTransformRowActionsButtonEnabled(transformId, false);
|
||||
}
|
||||
await transform.table.clearSearchString(testDataList.length);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
|
@ -272,10 +272,13 @@ export function TransformAPIProvider({ getService }: FtrProviderContext) {
|
|||
});
|
||||
},
|
||||
|
||||
async startTransform(transformId: string) {
|
||||
async startTransform(transformId: string, assertSuccess = true) {
|
||||
log.debug(`Starting transform '${transformId}' ...`);
|
||||
const { body, status } = await esSupertest.post(`/_transform/${transformId}/_start`);
|
||||
this.assertResponseStatusCode(200, status, body);
|
||||
|
||||
if (assertSuccess) {
|
||||
this.assertResponseStatusCode(200, status, body);
|
||||
}
|
||||
},
|
||||
|
||||
async stopTransform(transformId: string) {
|
||||
|
|
|
@ -32,6 +32,10 @@ export function TransformManagementProvider({ getService }: FtrProviderContext)
|
|||
await testSubjects.existOrFail('transformCreateFirstButton');
|
||||
},
|
||||
|
||||
async assertTransformsReauthorizeCalloutExists() {
|
||||
await testSubjects.existOrFail('transformPageReauthorizeCallout');
|
||||
},
|
||||
|
||||
async assertCreateFirstTransformButtonEnabled(expectedValue: boolean) {
|
||||
const isEnabled = await testSubjects.isEnabled('transformCreateFirstButton');
|
||||
expect(isEnabled).to.eql(
|
||||
|
|
|
@ -9,7 +9,15 @@ import expect from '@kbn/expect';
|
|||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
type TransformRowActionName = 'Clone' | 'Delete' | 'Discover' | 'Edit' | 'Reset' | 'Start' | 'Stop';
|
||||
type TransformRowActionName =
|
||||
| 'Clone'
|
||||
| 'Delete'
|
||||
| 'Discover'
|
||||
| 'Edit'
|
||||
| 'Reset'
|
||||
| 'Start'
|
||||
| 'Stop'
|
||||
| 'Reauthorize';
|
||||
|
||||
export function TransformTableProvider({ getService }: FtrProviderContext) {
|
||||
const find = getService('find');
|
||||
|
@ -464,6 +472,21 @@ export function TransformTableProvider({ getService }: FtrProviderContext) {
|
|||
});
|
||||
}
|
||||
|
||||
public async assertTransformRowActionMissing(
|
||||
transformId: string,
|
||||
action: TransformRowActionName
|
||||
) {
|
||||
const selector = `transformAction${action}`;
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await this.refreshTransformList();
|
||||
|
||||
await this.ensureTransformActionsMenuOpen(transformId);
|
||||
|
||||
await testSubjects.missingOrFail(selector, { timeout: 1000 });
|
||||
await this.ensureTransformActionsMenuClosed();
|
||||
});
|
||||
}
|
||||
|
||||
public async assertTransformRowActionEnabled(
|
||||
transformId: string,
|
||||
action: TransformRowActionName,
|
||||
|
@ -516,6 +539,14 @@ export function TransformTableProvider({ getService }: FtrProviderContext) {
|
|||
await testSubjects.missingOrFail('transformDeleteModal', { timeout: 60 * 1000 });
|
||||
}
|
||||
|
||||
public async assertTransformReauthorizeModalExists() {
|
||||
await testSubjects.existOrFail('transformReauthorizeModal', { timeout: 60 * 1000 });
|
||||
}
|
||||
|
||||
public async assertTransformReauthorizeModalNotExists() {
|
||||
await testSubjects.missingOrFail('transformReauthorizeModal', { timeout: 60 * 1000 });
|
||||
}
|
||||
|
||||
public async assertTransformResetModalExists() {
|
||||
await testSubjects.existOrFail('transformResetModal', { timeout: 60 * 1000 });
|
||||
}
|
||||
|
@ -564,6 +595,14 @@ export function TransformTableProvider({ getService }: FtrProviderContext) {
|
|||
});
|
||||
}
|
||||
|
||||
public async confirmReauthorizeTransform() {
|
||||
await retry.tryForTime(30 * 1000, async () => {
|
||||
await this.assertTransformReauthorizeModalExists();
|
||||
await testSubjects.click('transformReauthorizeModal > confirmModalConfirmButton');
|
||||
await this.assertTransformReauthorizeModalNotExists();
|
||||
});
|
||||
}
|
||||
|
||||
public async confirmStartTransform() {
|
||||
await retry.tryForTime(30 * 1000, async () => {
|
||||
await this.assertTransformStartModalExists();
|
||||
|
|
|
@ -16,8 +16,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
testFiles: [require.resolve('.')],
|
||||
junit: {
|
||||
...transformConfig.get('junit'),
|
||||
reportName:
|
||||
'Chrome X-Pack UI Functional Tests Basic License - transform - start reset & delete',
|
||||
reportName: 'Chrome X-Pack UI Functional Tests Basic License - transform - actions',
|
||||
},
|
||||
};
|
||||
}
|
|
@ -12,6 +12,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
|
|||
this.tags(['skipFirefox', 'transform']);
|
||||
|
||||
// The transform UI should work the same as with a trial license
|
||||
loadTestFile(require.resolve('../../../../functional/apps/transform/start_reset_delete'));
|
||||
loadTestFile(require.resolve('../../../../functional/apps/transform/actions'));
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue