diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/influencers/influencers_select.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/influencers/influencers_select.tsx index c7495054bdb27..63f1936dd5f3e 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/influencers/influencers_select.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/influencers/influencers_select.tsx @@ -35,6 +35,7 @@ export const InfluencersSelect: FC = ({ fields, changeHandler, selectedIn selectedOptions={selection} onChange={onChange} isClearable={false} + data-test-subj="influencerSelect" /> ); }; diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/settings.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/settings.tsx index 60e4cacd0adfd..5e800de755f26 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/settings.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/settings.tsx @@ -34,10 +34,10 @@ export const MultiMetricSettings: FC = ({ setIsValid }) => { return ( - + - + diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/chart_grid.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/chart_grid.tsx index 4af0b34030d9f..c809ebd115566 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/chart_grid.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/chart_grid.tsx @@ -49,7 +49,7 @@ export const ChartGrid: FC = ({ return ( {aggFieldPairList.map((af, i) => ( - + diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/by_field.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/by_field.tsx index 586d2202be81d..0acabe60b0049 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/by_field.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/by_field.tsx @@ -58,6 +58,7 @@ export const ByFieldSelector: FC = ({ detectorIndex }) => { changeHandler={setByField} selectedField={byField} isClearable={true} + testSubject="byFieldSelect" placeholder={i18n.translate( 'xpack.ml.newJob.wizard.pickFieldsStep.populationField.placeholder', { diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/split_field.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/split_field.tsx index e7bb575dc5b60..229072c314cc5 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/split_field.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/split_field.tsx @@ -48,6 +48,13 @@ export const SplitFieldSelector: FC = () => { changeHandler={setSplitField} selectedField={splitField} isClearable={canClearSelection} + testSubject={ + isMultiMetricJobCreator(jc) + ? 'multiMetricSplitFieldSelect' + : isPopulationJobCreator(jc) + ? 'populationSplitFieldSelect' + : undefined + } /> ); diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/split_field_select.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/split_field_select.tsx index c1b44ea6d7bef..0dc76be9f8f07 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/split_field_select.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/split_field_select.tsx @@ -19,6 +19,7 @@ interface Props { changeHandler(f: SplitField): void; selectedField: SplitField; isClearable: boolean; + testSubject?: string; placeholder?: string; } @@ -27,6 +28,7 @@ export const SplitFieldSelect: FC = ({ changeHandler, selectedField, isClearable, + testSubject, placeholder, }) => { const options: EuiComboBoxOptionProps[] = fields.map( @@ -59,6 +61,7 @@ export const SplitFieldSelect: FC = ({ onChange={onChange} isClearable={isClearable} placeholder={placeholder} + data-test-subj={testSubject} /> ); }; diff --git a/x-pack/test/functional/apps/machine_learning/create_multi_metric_job.ts b/x-pack/test/functional/apps/machine_learning/create_multi_metric_job.ts index ed1f7e97eb536..0eb9c7da21b96 100644 --- a/x-pack/test/functional/apps/machine_learning/create_multi_metric_job.ts +++ b/x-pack/test/functional/apps/machine_learning/create_multi_metric_job.ts @@ -46,7 +46,7 @@ export default function({ getService }: FtrProviderContext) { await ml.jobSourceSelection.selectSourceIndexPattern('farequote'); }); - it('loads the single metric job wizard page', async () => { + it('loads the multi metric job wizard page', async () => { await ml.jobTypeSelection.selectMultiMetricJob(); }); @@ -73,13 +73,13 @@ export default function({ getService }: FtrProviderContext) { }); it('inputs the split field and displays split cards', async () => { - await ml.jobWizardCommon.assertMultiMetricSplitFieldInputExists(); - await ml.jobWizardCommon.selectMultiMetricSplitField(splitField); - await ml.jobWizardCommon.assertMultiMetricSplitFieldSelection(splitField); + await ml.jobWizardMultiMetric.assertSplitFieldInputExists(); + await ml.jobWizardMultiMetric.selectSplitField(splitField); + await ml.jobWizardMultiMetric.assertSplitFieldSelection(splitField); - await ml.jobWizardCommon.assertDetectorSplitExists(splitField); - await ml.jobWizardCommon.assertDetectorSplitFrontCardTitle('AAL'); - await ml.jobWizardCommon.assertDetectorSplitNumberOfBackCards(9); + await ml.jobWizardMultiMetric.assertDetectorSplitExists(splitField); + await ml.jobWizardMultiMetric.assertDetectorSplitFrontCardTitle('AAL'); + await ml.jobWizardMultiMetric.assertDetectorSplitNumberOfBackCards(9); await ml.jobWizardCommon.assertInfluencerSelection([splitField]); }); diff --git a/x-pack/test/functional/apps/machine_learning/create_population_job.ts b/x-pack/test/functional/apps/machine_learning/create_population_job.ts new file mode 100644 index 0000000000000..d588c602db36e --- /dev/null +++ b/x-pack/test/functional/apps/machine_learning/create_population_job.ts @@ -0,0 +1,243 @@ +/* + * 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 expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function({ getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const ml = getService('ml'); + const log = getService('log'); + + const jobId = `ec_population_1_${Date.now()}`; + const jobDescription = + 'Create population job based on the ecommerce sample dataset with 2h bucketspan over customer_id' + + ' - detectors: (Mean(products.base_price) by customer_gender), (Mean(products.quantity) by category.leyword)'; + const jobGroups = ['automated', 'ecommerce', 'population']; + const populationField = 'customer_id'; + const detectors = [ + { + identifier: 'Mean(products.base_price)', + splitField: 'customer_gender', + frontCardTitle: 'FEMALE', + numberOfBackCards: 1, + }, + { + identifier: 'Mean(products.quantity)', + splitField: 'category.keyword', + frontCardTitle: "Men's Clothing", + numberOfBackCards: 5, + }, + ]; + const bucketSpan = '2h'; + const memoryLimit = '8MB'; + + describe('population job creation', function() { + this.tags(['smoke', 'mlqa']); + before(async () => { + await esArchiver.loadIfNeeded('ml/ecommerce'); + }); + + after(async () => { + await esArchiver.unload('ml/farequote'); + await ml.api.cleanMlIndices(); + await ml.api.cleanDataframeIndices(); + }); + + it('loads the job management page', async () => { + await ml.navigation.navigateToMl(); + await ml.navigation.navigateToJobManagement(); + }); + + it('loads the new job source selection page', async () => { + await ml.jobManagement.navigateToNewJobSourceSelection(); + }); + + it('loads the job type selection page', async () => { + await ml.jobSourceSelection.selectSourceIndexPattern('ecommerce'); + }); + + it('loads the population job wizard page', async () => { + await ml.jobTypeSelection.selectPopulationJob(); + }); + + it('displays the time range step', async () => { + await ml.jobWizardCommon.assertTimeRangeSectionExists(); + }); + + it('displays the event rate chart', async () => { + await ml.jobWizardCommon.clickUseFullDataButton(); + await ml.jobWizardCommon.assertEventRateChartExists(); + }); + + it('displays the pick fields step', async () => { + await ml.jobWizardCommon.clickNextButton(); + await ml.jobWizardCommon.assertPickFieldsSectionExists(); + }); + + it('selects the population field', async () => { + await ml.jobWizardPopulation.assertPopulationFieldInputExists(); + await ml.jobWizardPopulation.selectPopulationField(populationField); + await ml.jobWizardPopulation.assertPopulationFieldSelection(populationField); + }); + + it('selects detectors and displays detector previews', async () => { + for (const [index, detector] of detectors.entries()) { + await ml.jobWizardCommon.assertAggAndFieldInputExists(); + await ml.jobWizardCommon.selectAggAndField(detector.identifier); + await ml.jobWizardCommon.assertDetectorPreviewExists(detector.identifier, index, 'SCATTER'); + } + }); + + it('inputs detector split fields and displays split cards', async () => { + for (const [index, detector] of detectors.entries()) { + log.debug(detector); + await ml.jobWizardPopulation.assertDetectorSplitFieldInputExists(index); + await ml.jobWizardPopulation.selectDetectorSplitField(index, detector.splitField); + await ml.jobWizardPopulation.assertDetectorSplitFieldSelection(index, detector.splitField); + + await ml.jobWizardPopulation.assertDetectorSplitExists(index); + await ml.jobWizardPopulation.assertDetectorSplitFrontCardTitle( + index, + detector.frontCardTitle + ); + await ml.jobWizardPopulation.assertDetectorSplitNumberOfBackCards( + index, + detector.numberOfBackCards + ); + } + }); + + it('displays the influencer field', async () => { + await ml.jobWizardCommon.assertInfluencerInputExists(); + await ml.jobWizardCommon.assertInfluencerSelection( + [populationField].concat(detectors.map(detector => detector.splitField)) + ); + }); + + it('inputs the bucket span', async () => { + await ml.jobWizardCommon.assertBucketSpanInputExists(); + await ml.jobWizardCommon.setBucketSpan(bucketSpan); + await ml.jobWizardCommon.assertBucketSpanValue(bucketSpan); + }); + + it('displays the job details step', async () => { + await ml.jobWizardCommon.clickNextButton(); + await ml.jobWizardCommon.assertJobDetailsSectionExists(); + }); + + it('inputs the job id', async () => { + await ml.jobWizardCommon.assertJobIdInputExists(); + await ml.jobWizardCommon.setJobId(jobId); + await ml.jobWizardCommon.assertJobIdValue(jobId); + }); + + it('inputs the job description', async () => { + await ml.jobWizardCommon.assertJobDescriptionInputExists(); + await ml.jobWizardCommon.setJobDescription(jobDescription); + await ml.jobWizardCommon.assertJobDescriptionValue(jobDescription); + }); + + it('inputs job groups', async () => { + await ml.jobWizardCommon.assertJobGroupInputExists(); + for (const jobGroup of jobGroups) { + await ml.jobWizardCommon.addJobGroup(jobGroup); + } + await ml.jobWizardCommon.assertJobGroupSelection(jobGroups); + }); + + it('opens the advanced section', async () => { + await ml.jobWizardCommon.ensureAdvancedSectionOpen(); + }); + + it('displays the model plot switch', async () => { + await ml.jobWizardCommon.assertModelPlotSwitchExists(); + }); + + it('enables the dedicated index switch', async () => { + await ml.jobWizardCommon.assertDedicatedIndexSwitchExists(); + await ml.jobWizardCommon.activateDedicatedIndexSwitch(); + await ml.jobWizardCommon.assertDedicatedIndexSwitchCheckedState(true); + }); + + it('inputs the model memory limit', async () => { + await ml.jobWizardCommon.assertModelMemoryLimitInputExists(); + await ml.jobWizardCommon.setModelMemoryLimit(memoryLimit); + await ml.jobWizardCommon.assertModelMemoryLimitValue(memoryLimit); + }); + + it('displays the validation step', async () => { + await ml.jobWizardCommon.clickNextButton(); + await ml.jobWizardCommon.assertValidationSectionExists(); + }); + + it('displays the summary step', async () => { + await ml.jobWizardCommon.clickNextButton(); + await ml.jobWizardCommon.assertSummarySectionExists(); + }); + + it('creates the job and finishes processing', async () => { + await ml.jobWizardCommon.assertCreateJobButtonExists(); + await ml.jobWizardCommon.createJobAndWaitForCompletion(); + }); + + it('displays the created job in the job list', async () => { + await ml.navigation.navigateToMl(); + await ml.navigation.navigateToJobManagement(); + + await ml.jobTable.waitForJobsToLoad(); + await ml.jobTable.filterWithSearchString(jobId); + const rows = await ml.jobTable.parseJobTable(); + expect(rows.filter(row => row.id === jobId)).to.have.length(1); + }); + + it('displays details for the created job in the job list', async () => { + const expectedRow = { + id: jobId, + description: jobDescription, + jobGroups, + recordCount: '4,675', + memoryStatus: 'ok', + jobState: 'closed', + datafeedState: 'stopped', + latestTimestamp: '2019-07-12 23:45:36', + }; + await ml.jobTable.assertJobRowFields(jobId, expectedRow); + + const expectedCounts = { + job_id: jobId, + processed_record_count: '4,675', + processed_field_count: '23,375', + input_bytes: '867.7 KB', + input_field_count: '23,375', + invalid_date_count: '0', + missing_field_count: '0', + out_of_order_timestamp_count: '0', + empty_bucket_count: '0', + sparse_bucket_count: '0', + bucket_count: '371', + earliest_record_timestamp: '2019-06-12 00:04:19', + latest_record_timestamp: '2019-07-12 23:45:36', + input_record_count: '4,675', + latest_bucket_timestamp: '2019-07-12 22:00:00', + }; + const expectedModelSizeStats = { + job_id: jobId, + result_type: 'model_size_stats', + model_bytes_exceeded: '0', + model_bytes_memory_limit: '8388608', + total_by_field_count: '25', + total_over_field_count: '92', + total_partition_field_count: '3', + bucket_allocation_failures_count: '0', + memory_status: 'ok', + timestamp: '2019-07-12 20:00:00', + }; + await ml.jobTable.assertJobRowDetailsCounts(jobId, expectedCounts, expectedModelSizeStats); + }); + }); +} diff --git a/x-pack/test/functional/apps/machine_learning/index.ts b/x-pack/test/functional/apps/machine_learning/index.ts index 42cf2f35ee43f..5ddbfe59fb64d 100644 --- a/x-pack/test/functional/apps/machine_learning/index.ts +++ b/x-pack/test/functional/apps/machine_learning/index.ts @@ -13,5 +13,6 @@ export default function({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./pages')); loadTestFile(require.resolve('./create_single_metric_job')); loadTestFile(require.resolve('./create_multi_metric_job')); + loadTestFile(require.resolve('./create_population_job')); }); } diff --git a/x-pack/test/functional/es_archives/ml/ecommerce/data.json.gz b/x-pack/test/functional/es_archives/ml/ecommerce/data.json.gz new file mode 100644 index 0000000000000..b38981c03417e Binary files /dev/null and b/x-pack/test/functional/es_archives/ml/ecommerce/data.json.gz differ diff --git a/x-pack/test/functional/es_archives/ml/ecommerce/mappings.json b/x-pack/test/functional/es_archives/ml/ecommerce/mappings.json new file mode 100644 index 0000000000000..9e3275bd40bfe --- /dev/null +++ b/x-pack/test/functional/es_archives/ml/ecommerce/mappings.json @@ -0,0 +1,1226 @@ +{ + "type": "index", + "value": { + "aliases": { + }, + "index": "ecommerce", + "mappings": { + "properties": { + "category": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "currency": { + "type": "keyword" + }, + "customer_birth_date": { + "type": "date" + }, + "customer_first_name": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "customer_full_name": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "customer_gender": { + "type": "keyword" + }, + "customer_id": { + "type": "keyword" + }, + "customer_last_name": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "customer_phone": { + "type": "keyword" + }, + "day_of_week": { + "type": "keyword" + }, + "day_of_week_i": { + "type": "integer" + }, + "email": { + "type": "keyword" + }, + "geoip": { + "properties": { + "city_name": { + "type": "keyword" + }, + "continent_name": { + "type": "keyword" + }, + "country_iso_code": { + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "region_name": { + "type": "keyword" + } + } + }, + "manufacturer": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "order_date": { + "type": "date" + }, + "order_id": { + "type": "keyword" + }, + "products": { + "properties": { + "_id": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "base_price": { + "type": "half_float" + }, + "base_unit_price": { + "type": "half_float" + }, + "category": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "created_on": { + "type": "date" + }, + "discount_amount": { + "type": "half_float" + }, + "discount_percentage": { + "type": "half_float" + }, + "manufacturer": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "min_price": { + "type": "half_float" + }, + "price": { + "type": "half_float" + }, + "product_id": { + "type": "long" + }, + "product_name": { + "analyzer": "english", + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "quantity": { + "type": "integer" + }, + "sku": { + "type": "keyword" + }, + "tax_amount": { + "type": "half_float" + }, + "taxful_price": { + "type": "half_float" + }, + "taxless_price": { + "type": "half_float" + }, + "unit_discount_amount": { + "type": "half_float" + } + } + }, + "sku": { + "type": "keyword" + }, + "taxful_total_price": { + "type": "half_float" + }, + "taxless_total_price": { + "type": "half_float" + }, + "total_quantity": { + "type": "integer" + }, + "total_unique_products": { + "type": "integer" + }, + "type": { + "type": "keyword" + }, + "user": { + "type": "keyword" + } + } + }, + "settings": { + "index": { + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + ".kibana": { + } + }, + "index": ".kibana_1", + "mappings": { + "_meta": { + "migrationMappingPropertyHashes": { + "apm-telemetry": "07ee1939fa4302c62ddc052ec03fed90", + "canvas-element": "7390014e1091044523666d97247392fc", + "canvas-workpad": "b0a1706d356228dbdcb4a17e6b9eb231", + "config": "87aca8fdb053154f11383fce3dbf3edf", + "dashboard": "d00f614b29a80360e1190193fd333bab", + "file-upload-telemetry": "0ed4d3e1983d1217a30982630897092e", + "graph-workspace": "cd7ba1330e6682e9cc00b78850874be1", + "index-pattern": "66eccb05066c5a89924f48a9e9736499", + "infrastructure-ui-source": "ddc0ecb18383f6b26101a2fadb2dab0c", + "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", + "map": "23d7aa4a720d4938ccde3983f87bd58d", + "maps-telemetry": "a4229f8b16a6820c6d724b7e0c1f729d", + "migrationVersion": "4a1746014a75ade3a714e1db5763276f", + "ml-telemetry": "257fd1d4b4fdbb9cb4b8a3b27da201e9", + "namespace": "2f4316de49999235636386fe51dc06c1", + "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", + "references": "7997cf5a56cc02bdc9c93361bde732b0", + "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", + "search": "181661168bbadd1eff5902361e2a0d5c", + "server": "ec97f1c5da1a19609a60874e5af1100c", + "siem-ui-timeline": "1f6f0860ad7bc0dba3e42467ca40470d", + "siem-ui-timeline-note": "8874706eedc49059d4cf0f5094559084", + "siem-ui-timeline-pinned-event": "20638091112f0e14f0e443d512301c29", + "space": "25de8c2deec044392922989cfcf24c54", + "telemetry": "e1c8bc94e443aefd9458932cc0697a4d", + "timelion-sheet": "9a2a2748877c7a7b582fef201ab1d4cf", + "type": "2f4316de49999235636386fe51dc06c1", + "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", + "updated_at": "00da57df13e94e9d98437d13ace4bfe0", + "upgrade-assistant-reindex-operation": "a53a20fe086b72c9a86da3cc12dad8a6", + "upgrade-assistant-telemetry": "56702cec857e0a9dacfb696655b4ff7b", + "url": "c7f66a0df8b1b52f17c28c4adb111105", + "visualization": "52d7a13ad68a150c4525b292d23e12cc" + } + }, + "dynamic": "strict", + "properties": { + "apm-telemetry": { + "properties": { + "has_any_services": { + "type": "boolean" + }, + "services_per_agent": { + "properties": { + "dotnet": { + "null_value": 0, + "type": "long" + }, + "go": { + "null_value": 0, + "type": "long" + }, + "java": { + "null_value": 0, + "type": "long" + }, + "js-base": { + "null_value": 0, + "type": "long" + }, + "nodejs": { + "null_value": 0, + "type": "long" + }, + "python": { + "null_value": 0, + "type": "long" + }, + "ruby": { + "null_value": 0, + "type": "long" + }, + "rum-js": { + "null_value": 0, + "type": "long" + } + } + } + } + }, + "canvas-element": { + "dynamic": "false", + "properties": { + "@created": { + "type": "date" + }, + "@timestamp": { + "type": "date" + }, + "content": { + "type": "text" + }, + "help": { + "type": "text" + }, + "image": { + "type": "text" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "canvas-workpad": { + "dynamic": "false", + "properties": { + "@created": { + "type": "date" + }, + "@timestamp": { + "type": "date" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "config": { + "dynamic": "true", + "properties": { + "buildNum": { + "type": "keyword" + }, + "dateFormat:tz": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "defaultIndex": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "dashboard": { + "properties": { + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "optionsJSON": { + "type": "text" + }, + "panelsJSON": { + "type": "text" + }, + "refreshInterval": { + "properties": { + "display": { + "type": "keyword" + }, + "pause": { + "type": "boolean" + }, + "section": { + "type": "integer" + }, + "value": { + "type": "integer" + } + } + }, + "timeFrom": { + "type": "keyword" + }, + "timeRestore": { + "type": "boolean" + }, + "timeTo": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "file-upload-telemetry": { + "properties": { + "filesUploadedTotalCount": { + "type": "long" + } + } + }, + "graph-workspace": { + "properties": { + "description": { + "type": "text" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "numLinks": { + "type": "integer" + }, + "numVertices": { + "type": "integer" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + }, + "wsState": { + "type": "text" + } + } + }, + "index-pattern": { + "properties": { + "fieldFormatMap": { + "type": "text" + }, + "fields": { + "type": "text" + }, + "intervalName": { + "type": "keyword" + }, + "notExpandable": { + "type": "boolean" + }, + "sourceFilters": { + "type": "text" + }, + "timeFieldName": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "type": { + "type": "keyword" + }, + "typeMeta": { + "type": "keyword" + } + } + }, + "infrastructure-ui-source": { + "properties": { + "description": { + "type": "text" + }, + "fields": { + "properties": { + "container": { + "type": "keyword" + }, + "host": { + "type": "keyword" + }, + "pod": { + "type": "keyword" + }, + "tiebreaker": { + "type": "keyword" + }, + "timestamp": { + "type": "keyword" + } + } + }, + "logAlias": { + "type": "keyword" + }, + "logColumns": { + "properties": { + "fieldColumn": { + "properties": { + "field": { + "type": "keyword" + }, + "id": { + "type": "keyword" + } + } + }, + "messageColumn": { + "properties": { + "id": { + "type": "keyword" + } + } + }, + "timestampColumn": { + "properties": { + "id": { + "type": "keyword" + } + } + } + }, + "type": "nested" + }, + "metricAlias": { + "type": "keyword" + }, + "name": { + "type": "text" + } + } + }, + "kql-telemetry": { + "properties": { + "optInCount": { + "type": "long" + }, + "optOutCount": { + "type": "long" + } + } + }, + "map": { + "properties": { + "bounds": { + "type": "geo_shape" + }, + "description": { + "type": "text" + }, + "layerListJSON": { + "type": "text" + }, + "mapStateJSON": { + "type": "text" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "maps-telemetry": { + "properties": { + "attributesPerMap": { + "properties": { + "dataSourcesCount": { + "properties": { + "avg": { + "type": "long" + }, + "max": { + "type": "long" + }, + "min": { + "type": "long" + } + } + }, + "emsVectorLayersCount": { + "dynamic": "true", + "type": "object" + }, + "layerTypesCount": { + "dynamic": "true", + "type": "object" + }, + "layersCount": { + "properties": { + "avg": { + "type": "long" + }, + "max": { + "type": "long" + }, + "min": { + "type": "long" + } + } + } + } + }, + "mapsTotalCount": { + "type": "long" + }, + "timeCaptured": { + "type": "date" + } + } + }, + "migrationVersion": { + "dynamic": "true", + "properties": { + "index-pattern": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "space": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "ml-telemetry": { + "properties": { + "file_data_visualizer": { + "properties": { + "index_creation_count": { + "type": "long" + } + } + } + } + }, + "namespace": { + "type": "keyword" + }, + "query": { + "properties": { + "description": { + "type": "text" + }, + "filters": { + "enabled": false, + "type": "object" + }, + "query": { + "properties": { + "language": { + "type": "keyword" + }, + "query": { + "index": false, + "type": "keyword" + } + } + }, + "timefilter": { + "enabled": false, + "type": "object" + }, + "title": { + "type": "text" + } + } + }, + "references": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "sample-data-telemetry": { + "properties": { + "installCount": { + "type": "long" + }, + "unInstallCount": { + "type": "long" + } + } + }, + "search": { + "properties": { + "columns": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "sort": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "server": { + "properties": { + "uuid": { + "type": "keyword" + } + } + }, + "siem-ui-timeline": { + "properties": { + "columns": { + "properties": { + "aggregatable": { + "type": "boolean" + }, + "category": { + "type": "keyword" + }, + "columnHeaderType": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "example": { + "type": "text" + }, + "id": { + "type": "keyword" + }, + "indexes": { + "type": "keyword" + }, + "name": { + "type": "text" + }, + "placeholder": { + "type": "text" + }, + "searchable": { + "type": "boolean" + }, + "type": { + "type": "keyword" + } + } + }, + "created": { + "type": "date" + }, + "createdBy": { + "type": "text" + }, + "dataProviders": { + "properties": { + "and": { + "properties": { + "enabled": { + "type": "boolean" + }, + "excluded": { + "type": "boolean" + }, + "id": { + "type": "keyword" + }, + "kqlQuery": { + "type": "text" + }, + "name": { + "type": "text" + }, + "queryMatch": { + "properties": { + "displayField": { + "type": "text" + }, + "displayValue": { + "type": "text" + }, + "field": { + "type": "text" + }, + "operator": { + "type": "text" + }, + "value": { + "type": "text" + } + } + } + } + }, + "enabled": { + "type": "boolean" + }, + "excluded": { + "type": "boolean" + }, + "id": { + "type": "keyword" + }, + "kqlQuery": { + "type": "text" + }, + "name": { + "type": "text" + }, + "queryMatch": { + "properties": { + "displayField": { + "type": "text" + }, + "displayValue": { + "type": "text" + }, + "field": { + "type": "text" + }, + "operator": { + "type": "text" + }, + "value": { + "type": "text" + } + } + } + } + }, + "dateRange": { + "properties": { + "end": { + "type": "date" + }, + "start": { + "type": "date" + } + } + }, + "description": { + "type": "text" + }, + "favorite": { + "properties": { + "favoriteDate": { + "type": "date" + }, + "fullName": { + "type": "text" + }, + "keySearch": { + "type": "text" + }, + "userName": { + "type": "text" + } + } + }, + "kqlMode": { + "type": "keyword" + }, + "kqlQuery": { + "properties": { + "filterQuery": { + "properties": { + "kuery": { + "properties": { + "expression": { + "type": "text" + }, + "kind": { + "type": "keyword" + } + } + }, + "serializedQuery": { + "type": "text" + } + } + } + } + }, + "sort": { + "properties": { + "columnId": { + "type": "keyword" + }, + "sortDirection": { + "type": "keyword" + } + } + }, + "title": { + "type": "text" + }, + "updated": { + "type": "date" + }, + "updatedBy": { + "type": "text" + } + } + }, + "siem-ui-timeline-note": { + "properties": { + "created": { + "type": "date" + }, + "createdBy": { + "type": "text" + }, + "eventId": { + "type": "keyword" + }, + "note": { + "type": "text" + }, + "timelineId": { + "type": "keyword" + }, + "updated": { + "type": "date" + }, + "updatedBy": { + "type": "text" + } + } + }, + "siem-ui-timeline-pinned-event": { + "properties": { + "created": { + "type": "date" + }, + "createdBy": { + "type": "text" + }, + "eventId": { + "type": "keyword" + }, + "timelineId": { + "type": "keyword" + }, + "updated": { + "type": "date" + }, + "updatedBy": { + "type": "text" + } + } + }, + "space": { + "properties": { + "_reserved": { + "type": "boolean" + }, + "color": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "disabledFeatures": { + "type": "keyword" + }, + "initials": { + "type": "keyword" + }, + "name": { + "fields": { + "keyword": { + "ignore_above": 2048, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "telemetry": { + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "timelion-sheet": { + "properties": { + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "timelion_chart_height": { + "type": "integer" + }, + "timelion_columns": { + "type": "integer" + }, + "timelion_interval": { + "type": "keyword" + }, + "timelion_other_interval": { + "type": "keyword" + }, + "timelion_rows": { + "type": "integer" + }, + "timelion_sheet": { + "type": "text" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "type": { + "type": "keyword" + }, + "ui-metric": { + "properties": { + "count": { + "type": "integer" + } + } + }, + "updated_at": { + "type": "date" + }, + "upgrade-assistant-reindex-operation": { + "dynamic": "true", + "properties": { + "indexName": { + "type": "keyword" + }, + "status": { + "type": "integer" + } + } + }, + "upgrade-assistant-telemetry": { + "properties": { + "features": { + "properties": { + "deprecation_logging": { + "properties": { + "enabled": { + "null_value": true, + "type": "boolean" + } + } + } + } + }, + "ui_open": { + "properties": { + "cluster": { + "null_value": 0, + "type": "long" + }, + "indices": { + "null_value": 0, + "type": "long" + }, + "overview": { + "null_value": 0, + "type": "long" + } + } + }, + "ui_reindex": { + "properties": { + "close": { + "null_value": 0, + "type": "long" + }, + "open": { + "null_value": 0, + "type": "long" + }, + "start": { + "null_value": 0, + "type": "long" + }, + "stop": { + "null_value": 0, + "type": "long" + } + } + } + } + }, + "url": { + "properties": { + "accessCount": { + "type": "long" + }, + "accessDate": { + "type": "date" + }, + "createDate": { + "type": "date" + }, + "url": { + "fields": { + "keyword": { + "ignore_above": 2048, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "visualization": { + "properties": { + "description": { + "type": "text" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "savedSearchRefName": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "type": "text" + }, + "version": { + "type": "integer" + }, + "visState": { + "type": "text" + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } +} \ No newline at end of file diff --git a/x-pack/test/functional/services/machine_learning/index.ts b/x-pack/test/functional/services/machine_learning/index.ts index f6fab4af1a119..56b0e835124de 100644 --- a/x-pack/test/functional/services/machine_learning/index.ts +++ b/x-pack/test/functional/services/machine_learning/index.ts @@ -13,6 +13,8 @@ export { MachineLearningJobSourceSelectionProvider } from './job_source_selectio export { MachineLearningJobTableProvider } from './job_table'; export { MachineLearningJobTypeSelectionProvider } from './job_type_selection'; export { MachineLearningJobWizardCommonProvider } from './job_wizard_common'; +export { MachineLearningJobWizardMultiMetricProvider } from './job_wizard_multi_metric'; +export { MachineLearningJobWizardPopulationProvider } from './job_wizard_population'; export { MachineLearningNavigationProvider } from './navigation'; export { MachineLearningSettingsProvider } from './settings'; export { MachineLearningSingleMetricViewerProvider } from './single_metric_viewer'; diff --git a/x-pack/test/functional/services/machine_learning/job_type_selection.ts b/x-pack/test/functional/services/machine_learning/job_type_selection.ts index c488c6bc5168f..eedcdcfea119e 100644 --- a/x-pack/test/functional/services/machine_learning/job_type_selection.ts +++ b/x-pack/test/functional/services/machine_learning/job_type_selection.ts @@ -19,5 +19,10 @@ export function MachineLearningJobTypeSelectionProvider({ getService }: FtrProvi await testSubjects.clickWhenNotDisabled('mlJobTypeLinkMultiMetricJob'); await testSubjects.existOrFail('mlPageJobWizard'); }, + + async selectPopulationJob() { + await testSubjects.clickWhenNotDisabled('mlJobTypeLinkPopulationJob'); + await testSubjects.existOrFail('mlPageJobWizard'); + }, }; } diff --git a/x-pack/test/functional/services/machine_learning/job_wizard_common.ts b/x-pack/test/functional/services/machine_learning/job_wizard_common.ts index 18eb9f720deae..d6e09e8c818f7 100644 --- a/x-pack/test/functional/services/machine_learning/job_wizard_common.ts +++ b/x-pack/test/functional/services/machine_learning/job_wizard_common.ts @@ -140,25 +140,13 @@ export function MachineLearningJobWizardCommonProvider({ getService }: FtrProvid expect(actualModelMemoryLimit).to.eql(expectedValue); }, - async assertMultiMetricSplitFieldInputExists() { - await testSubjects.existOrFail('mlJobWizardSplitFieldSelection > comboBoxInput'); - }, - - async assertMultiMetricSplitFieldSelection(identifier: string) { - const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( - 'mlJobWizardSplitFieldSelection > comboBoxInput' - ); - expect(comboBoxSelectedOptions.length).to.eql(1); - expect(comboBoxSelectedOptions[0]).to.eql(identifier); - }, - async assertInfluencerInputExists() { - await testSubjects.existOrFail('mlJobWizardInfluencerSelection > comboBoxInput'); + await testSubjects.existOrFail('influencerSelect > comboBoxInput'); }, async assertInfluencerSelection(influencers: string[]) { const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( - 'mlJobWizardInfluencerSelection > comboBoxInput' + 'influencerSelect > comboBoxInput' ); expect(comboBoxSelectedOptions).to.eql(influencers); }, @@ -176,24 +164,6 @@ export function MachineLearningJobWizardCommonProvider({ getService }: FtrProvid await testSubjects.existOrFail(`detector ${detectorPosition} > mlAnomalyChart ${chartType}`); }, - async assertDetectorSplitExists(splitField: string) { - await testSubjects.existOrFail(`dataSplit > dataSplitTitle ${splitField}`); - await testSubjects.existOrFail(`dataSplit > splitCard front`); - await testSubjects.existOrFail(`dataSplit > splitCard back`); - }, - - async assertDetectorSplitFrontCardTitle(frontCardTitle: string) { - expect( - await testSubjects.getVisibleText(`dataSplit > splitCard front > splitCardTitle`) - ).to.eql(frontCardTitle); - }, - - async assertDetectorSplitNumberOfBackCards(numberOfBackCards: number) { - expect(await testSubjects.findAll(`dataSplit > splitCard back`)).to.have.length( - numberOfBackCards - ); - }, - async clickNextButton() { await testSubjects.clickWhenNotDisabled('mlJobWizardNavButtonNext'); }, @@ -226,12 +196,8 @@ export function MachineLearningJobWizardCommonProvider({ getService }: FtrProvid await comboBox.setCustom('mlJobWizardComboBoxJobGroups > comboBoxInput', jobGroup); }, - async selectMultiMetricSplitField(identifier: string) { - await comboBox.set('mlJobWizardSplitFieldSelection > comboBoxInput', identifier); - }, - async addInfluencer(influencer: string) { - await comboBox.setCustom('mlJobWizardInfluencerSelection > comboBoxInput', influencer); + await comboBox.setCustom('influencerSelect > comboBoxInput', influencer); }, async ensureAdvancedSectionOpen() { diff --git a/x-pack/test/functional/services/machine_learning/job_wizard_multi_metric.ts b/x-pack/test/functional/services/machine_learning/job_wizard_multi_metric.ts new file mode 100644 index 0000000000000..f1e6319d6e866 --- /dev/null +++ b/x-pack/test/functional/services/machine_learning/job_wizard_multi_metric.ts @@ -0,0 +1,48 @@ +/* + * 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 expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export function MachineLearningJobWizardMultiMetricProvider({ getService }: FtrProviderContext) { + const comboBox = getService('comboBox'); + const testSubjects = getService('testSubjects'); + + return { + async assertSplitFieldInputExists() { + await testSubjects.existOrFail('multiMetricSplitFieldSelect > comboBoxInput'); + }, + + async assertSplitFieldSelection(identifier: string) { + const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( + 'multiMetricSplitFieldSelect > comboBoxInput' + ); + expect(comboBoxSelectedOptions.length).to.eql(1); + expect(comboBoxSelectedOptions[0]).to.eql(identifier); + }, + + async selectSplitField(identifier: string) { + await comboBox.set('multiMetricSplitFieldSelect > comboBoxInput', identifier); + }, + + async assertDetectorSplitExists(splitField: string) { + await testSubjects.existOrFail(`dataSplit > dataSplitTitle ${splitField}`); + await testSubjects.existOrFail(`dataSplit > splitCard front`); + }, + + async assertDetectorSplitFrontCardTitle(frontCardTitle: string) { + expect( + await testSubjects.getVisibleText(`dataSplit > splitCard front > splitCardTitle`) + ).to.eql(frontCardTitle); + }, + + async assertDetectorSplitNumberOfBackCards(numberOfBackCards: number) { + expect(await testSubjects.findAll(`dataSplit > splitCard back`)).to.have.length( + numberOfBackCards + ); + }, + }; +} diff --git a/x-pack/test/functional/services/machine_learning/job_wizard_population.ts b/x-pack/test/functional/services/machine_learning/job_wizard_population.ts new file mode 100644 index 0000000000000..12e59e0d5279d --- /dev/null +++ b/x-pack/test/functional/services/machine_learning/job_wizard_population.ts @@ -0,0 +1,74 @@ +/* + * 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 expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export function MachineLearningJobWizardPopulationProvider({ getService }: FtrProviderContext) { + const comboBox = getService('comboBox'); + const testSubjects = getService('testSubjects'); + + return { + async assertPopulationFieldInputExists() { + await testSubjects.existOrFail('populationSplitFieldSelect > comboBoxInput'); + }, + + async assertPopulationFieldSelection(identifier: string) { + const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( + 'populationSplitFieldSelect > comboBoxInput' + ); + expect(comboBoxSelectedOptions.length).to.eql(1); + expect(comboBoxSelectedOptions[0]).to.eql(identifier); + }, + + async selectPopulationField(identifier: string) { + await comboBox.set('populationSplitFieldSelect > comboBoxInput', identifier); + }, + + async assertDetectorSplitFieldInputExists(detectorPosition: number) { + await testSubjects.existOrFail( + `detector ${detectorPosition} > byFieldSelect > comboBoxInput` + ); + }, + + async assertDetectorSplitFieldSelection(detectorPosition: number, identifier: string) { + const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( + `detector ${detectorPosition} > byFieldSelect > comboBoxInput` + ); + expect(comboBoxSelectedOptions.length).to.eql(1); + expect(comboBoxSelectedOptions[0]).to.eql(identifier); + }, + + async selectDetectorSplitField(detectorPosition: number, identifier: string) { + await comboBox.set( + `detector ${detectorPosition} > byFieldSelect > comboBoxInput`, + identifier + ); + }, + + async assertDetectorSplitExists(detectorPosition: number) { + await testSubjects.existOrFail(`detector ${detectorPosition} > dataSplit`); + await testSubjects.existOrFail(`detector ${detectorPosition} > dataSplit > splitCard front`); + }, + + async assertDetectorSplitFrontCardTitle(detectorPosition: number, frontCardTitle: string) { + expect( + await testSubjects.getVisibleText( + `detector ${detectorPosition} > dataSplit > splitCard front > splitCardTitle` + ) + ).to.eql(frontCardTitle); + }, + + async assertDetectorSplitNumberOfBackCards( + detectorPosition: number, + numberOfBackCards: number + ) { + expect( + await testSubjects.findAll(`detector ${detectorPosition} > dataSplit > splitCard back`) + ).to.have.length(numberOfBackCards); + }, + }; +} diff --git a/x-pack/test/functional/services/ml.ts b/x-pack/test/functional/services/ml.ts index 6e929bd4e21e2..c063a48b81eaa 100644 --- a/x-pack/test/functional/services/ml.ts +++ b/x-pack/test/functional/services/ml.ts @@ -16,6 +16,8 @@ import { MachineLearningJobTableProvider, MachineLearningJobTypeSelectionProvider, MachineLearningJobWizardCommonProvider, + MachineLearningJobWizardMultiMetricProvider, + MachineLearningJobWizardPopulationProvider, MachineLearningNavigationProvider, MachineLearningSettingsProvider, MachineLearningSingleMetricViewerProvider, @@ -31,6 +33,8 @@ export function MachineLearningProvider(context: FtrProviderContext) { const jobTable = MachineLearningJobTableProvider(context); const jobTypeSelection = MachineLearningJobTypeSelectionProvider(context); const jobWizardCommon = MachineLearningJobWizardCommonProvider(context); + const jobWizardMultiMetric = MachineLearningJobWizardMultiMetricProvider(context); + const jobWizardPopulation = MachineLearningJobWizardPopulationProvider(context); const navigation = MachineLearningNavigationProvider(context); const settings = MachineLearningSettingsProvider(context); const singleMetricViewer = MachineLearningSingleMetricViewerProvider(context); @@ -45,6 +49,8 @@ export function MachineLearningProvider(context: FtrProviderContext) { jobTable, jobTypeSelection, jobWizardCommon, + jobWizardMultiMetric, + jobWizardPopulation, navigation, settings, singleMetricViewer,