diff --git a/x-pack/test/functional/apps/transform/cloning.ts b/x-pack/test/functional/apps/transform/cloning.ts new file mode 100644 index 0000000000000..f06dc0a14a383 --- /dev/null +++ b/x-pack/test/functional/apps/transform/cloning.ts @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; +import { TransformPivotConfig } from '../../../../legacy/plugins/transform/public/app/common'; + +function getTransformConfig(): TransformPivotConfig { + const date = Date.now(); + return { + id: `ec_2_${date}`, + source: { index: ['ecommerce'] }, + pivot: { + group_by: { category: { terms: { field: 'category.keyword' } } }, + aggregations: { 'products.base_price.avg': { avg: { field: 'products.base_price' } } }, + }, + description: + 'ecommerce batch transform with avg(products.base_price) grouped by terms(category.keyword)', + dest: { index: `user-ec_2_${date}` }, + }; +} + +export default function({ getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const transform = getService('transform'); + + describe('cloning', function() { + this.tags(['smoke']); + const transformConfig = getTransformConfig(); + + before(async () => { + await esArchiver.load('ml/ecommerce'); + await transform.api.createAndRunTransform(transformConfig); + await transform.securityUI.loginAsTransformPowerUser(); + }); + + after(async () => { + await esArchiver.unload('ml/ecommerce'); + await transform.api.deleteIndices(transformConfig.dest.index); + await transform.api.cleanTransformIndices(); + }); + + const testDataList = [ + { + suiteTitle: 'batch transform with terms group and avg agg', + expected: {}, + }, + ]; + + for (const testData of testDataList) { + describe(`${testData.suiteTitle}`, function() { + after(async () => { + // await transform.api.deleteIndices(); + }); + + it('loads the home page', async () => { + await transform.navigation.navigateTo(); + await transform.management.assertTransformListPageExists(); + }); + }); + } + }); +} diff --git a/x-pack/test/functional/apps/transform/index.ts b/x-pack/test/functional/apps/transform/index.ts index 66a55105b3ca8..60b72f122f113 100644 --- a/x-pack/test/functional/apps/transform/index.ts +++ b/x-pack/test/functional/apps/transform/index.ts @@ -23,5 +23,6 @@ export default function({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./creation_index_pattern')); loadTestFile(require.resolve('./creation_saved_search')); + loadTestFile(require.resolve('./cloning')); }); } diff --git a/x-pack/test/functional/services/transform_ui/api.ts b/x-pack/test/functional/services/transform_ui/api.ts index a6756e5940d72..6a4a1dfff6ea1 100644 --- a/x-pack/test/functional/services/transform_ui/api.ts +++ b/x-pack/test/functional/services/transform_ui/api.ts @@ -7,10 +7,17 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; +import { + TRANSFORM_STATE, + TransformPivotConfig, + TransformStats, +} from '../../../../legacy/plugins/transform/public/app/common'; + export function TransformAPIProvider({ getService }: FtrProviderContext) { const es = getService('legacyEs'); const log = getService('log'); const retry = getService('retry'); + const esSupertest = getService('esSupertest'); return { async deleteIndices(indices: string) { @@ -39,5 +46,89 @@ export function TransformAPIProvider({ getService }: FtrProviderContext) { async cleanTransformIndices() { await this.deleteIndices('.transform-*'); }, + + async getTransformStats(transformId: string): Promise { + log.debug(`Fetching transform stats for transform ${transformId}`); + const statsResponse = await esSupertest + .get(`/_transform/${transformId}/_stats`) + .expect(200) + .then((res: any) => res.body); + + expect(statsResponse.transforms).to.have.length(1); + return statsResponse.transforms[0]; + }, + + async getTransformState(transformId: string): Promise { + const stats = await this.getTransformStats(transformId); + const state: TRANSFORM_STATE = stats.state; + + return state; + }, + + async waitForTransformState(transformId: string, expectedState: TRANSFORM_STATE) { + await retry.waitForWithTimeout( + `transform state to be ${expectedState}`, + 2 * 60 * 1000, + async () => { + const state = await this.getTransformState(transformId); + if (state === expectedState) { + return true; + } else { + throw new Error(`expected transform state to be ${expectedState} but got ${state}`); + } + } + ); + }, + + async waitForBatchTransformToComplete(transformId: string) { + await retry.waitForWithTimeout(`batch transform to complete`, 2 * 60 * 1000, async () => { + const stats = await this.getTransformStats(transformId); + if (stats.state === TRANSFORM_STATE.STOPPED && stats.checkpointing.last.checkpoint === 1) { + return true; + } else { + throw new Error( + `expected batch transform to be stopped with last checkpoint = 1 (got status: '${stats.state}', checkpoint: '${stats.checkpointing.last.checkpoint}')` + ); + } + }); + }, + + async getTransform(transformId: string) { + return await esSupertest.get(`/_transform/${transformId}`).expect(200); + }, + + async createTransform(transformConfig: TransformPivotConfig) { + const transformId = transformConfig.id; + log.debug(`Creating transform with id '${transformId}'...`); + await esSupertest + .put(`/_transform/${transformId}`) + .send(transformConfig) + .expect(200); + + await retry.waitForWithTimeout(`'${transformId}' to be created`, 5 * 1000, async () => { + if (await this.getTransform(transformId)) { + return true; + } else { + throw new Error(`expected transform '${transformId}' to be created`); + } + }); + }, + + async startTransform(transformId: string) { + log.debug(`Starting transform '${transformId}' ...`); + await esSupertest.post(`/_transform/${transformId}/_start`).expect(200); + }, + + async createAndRunTransform(transformConfig: TransformPivotConfig) { + await this.createTransform(transformConfig); + await this.startTransform(transformConfig.id); + if (transformConfig.sync === undefined) { + // batch mode + await this.waitForBatchTransformToComplete(transformConfig.id); + } else { + // continuous mode + await this.waitForTransformState(transformConfig.id, TRANSFORM_STATE.STARTED); + } + }, }; }