Fix UI datasources view edit action compaction (#10459)

Restore the web console's ability to view a datasource's compaction
configuration via the "action" menu. Refactoring done in
https://github.com/apache/druid/pull/10438 introduced a regression that
always caused the default compaction configuration to be shown via the
"action" menu instead.

Regression test is added in e2e-tests/auto-compaction.spec.ts.
This commit is contained in:
Chi Cao Minh 2020-10-01 23:59:21 -07:00 committed by GitHub
parent 7385af0272
commit ede25f1b45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 104 additions and 11 deletions

View File

@ -126,6 +126,11 @@ async function configureCompaction(
) {
const datasourcesOverview = new DatasourcesOverview(page, UNIFIED_CONSOLE_URL);
await datasourcesOverview.setCompactionConfiguration(datasourceName, compactionConfig);
const savedCompactionConfig = await datasourcesOverview.getCompactionConfiguration(
datasourceName,
);
expect(savedCompactionConfig).toEqual(compactionConfig);
}
async function triggerCompaction() {

View File

@ -19,8 +19,10 @@
import * as playwright from 'playwright-core';
import { clickButton } from '../../util/playwright';
import { getLabeledInput } from '../../util/playwright';
import { setLabeledInput } from '../../util/playwright';
import { extractTable } from '../../util/table';
import { readPartitionSpec } from '../load-data/config/partition';
import { CompactionConfig } from './compaction';
import { Datasource } from './datasource';
@ -42,6 +44,9 @@ enum DatasourceColumn {
ACTIONS,
}
const EDIT_COMPACTION_CONFIGURATION = 'Edit compaction configuration';
const SKIP_OFFSET_FROM_LATEST = 'Skip offset from latest';
/**
* Represents datasource overview tab.
*/
@ -80,10 +85,10 @@ export class DatasourcesOverview {
): Promise<void> {
await this.openEditActions(datasourceName);
await this.page.click('"Edit compaction configuration"');
await this.page.click(`"${EDIT_COMPACTION_CONFIGURATION}"`);
await setLabeledInput(
this.page,
'Skip offset from latest',
SKIP_OFFSET_FROM_LATEST,
compactionConfig.skipOffsetFromLatest,
);
await compactionConfig.partitionsSpec.apply(this.page);
@ -91,6 +96,17 @@ export class DatasourcesOverview {
await clickButton(this.page, 'Submit');
}
async getCompactionConfiguration(datasourceName: string): Promise<CompactionConfig> {
await this.openEditActions(datasourceName);
await this.page.click(`"${EDIT_COMPACTION_CONFIGURATION}"`);
const skipOffsetFromLatest = await getLabeledInput(this.page, SKIP_OFFSET_FROM_LATEST);
const partitionsSpec = await readPartitionSpec(this.page);
await clickButton(this.page, 'Close');
return new CompactionConfig({ skipOffsetFromLatest, partitionsSpec: partitionsSpec! });
}
private async openEditActions(datasourceName: string): Promise<void> {
const datasources = await this.getDatasources();
const index = datasources.findIndex(t => t.name === datasourceName);
@ -100,6 +116,6 @@ export class DatasourcesOverview {
const editActions = await this.page.$$('span[icon=wrench]');
editActions[index].click();
await this.page.waitFor(5000);
await this.page.waitFor('ul.bp3-menu');
}
}

View File

@ -19,6 +19,7 @@
import * as playwright from 'playwright-core';
import { selectSuggestibleInput } from '../../../util/playwright';
import { getLabeledInput } from '../../../util/playwright';
import { setLabeledInput } from '../../../util/playwright';
/* tslint:disable max-classes-per-file */
@ -40,22 +41,49 @@ export interface PartitionsSpec {
apply(page: playwright.Page): Promise<void>;
}
export async function readPartitionSpec(page: playwright.Page): Promise<PartitionsSpec | null> {
const type = await getLabeledInput(page, PARTITIONING_TYPE);
switch (type) {
case HashedPartitionsSpec.TYPE:
return HashedPartitionsSpec.read(page);
case SingleDimPartitionsSpec.TYPE:
return SingleDimPartitionsSpec.read(page);
}
return null;
}
export class HashedPartitionsSpec implements PartitionsSpec {
public static TYPE = 'hashed';
private static NUM_SHARDS = 'Num shards';
readonly type: string;
static async read(page: playwright.Page): Promise<HashedPartitionsSpec> {
const numShards = await getLabeledInputAsNumber(page, HashedPartitionsSpec.NUM_SHARDS);
return new HashedPartitionsSpec({ numShards });
}
constructor(props: HashedPartitionsSpecProps) {
Object.assign(this, props);
this.type = 'hashed';
this.type = HashedPartitionsSpec.TYPE;
}
async apply(page: playwright.Page): Promise<void> {
await setLabeledInput(page, PARTITIONING_TYPE, this.type);
if (this.numShards != null) {
await setLabeledInput(page, 'Num shards', String(this.numShards));
await setLabeledInput(page, HashedPartitionsSpec.NUM_SHARDS, String(this.numShards));
}
}
}
async function getLabeledInputAsNumber(
page: playwright.Page,
label: string,
): Promise<number | null> {
const valueString = await getLabeledInput(page, label);
return valueString === '' ? null : Number(valueString);
}
interface HashedPartitionsSpecProps {
readonly numShards: number | null;
}
@ -63,21 +91,58 @@ interface HashedPartitionsSpecProps {
export interface HashedPartitionsSpec extends HashedPartitionsSpecProps {}
export class SingleDimPartitionsSpec implements PartitionsSpec {
public static TYPE = 'single_dim';
private static PARTITION_DIMENSION = 'Partition dimension';
private static TARGET_ROWS_PER_SEGMENT = 'Target rows per segment';
private static MAX_ROWS_PER_SEGMENT = 'Max rows per segment';
readonly type: string;
static async read(page: playwright.Page): Promise<SingleDimPartitionsSpec> {
const partitionDimension = await getLabeledInput(
page,
SingleDimPartitionsSpec.PARTITION_DIMENSION,
);
const targetRowsPerSegment = await getLabeledInputAsNumber(
page,
SingleDimPartitionsSpec.TARGET_ROWS_PER_SEGMENT,
);
const maxRowsPerSegment = await getLabeledInputAsNumber(
page,
SingleDimPartitionsSpec.MAX_ROWS_PER_SEGMENT,
);
return new SingleDimPartitionsSpec({
partitionDimension,
targetRowsPerSegment,
maxRowsPerSegment,
});
}
constructor(props: SingleDimPartitionsSpecProps) {
Object.assign(this, props);
this.type = 'single_dim';
this.type = SingleDimPartitionsSpec.TYPE;
}
async apply(page: playwright.Page): Promise<void> {
await selectSuggestibleInput(page, PARTITIONING_TYPE, this.type);
await setLabeledInput(page, 'Partition dimension', this.partitionDimension);
await setLabeledInput(
page,
SingleDimPartitionsSpec.PARTITION_DIMENSION,
this.partitionDimension,
);
if (this.targetRowsPerSegment) {
await setLabeledInput(page, 'Target rows per segment', String(this.targetRowsPerSegment));
await setLabeledInput(
page,
SingleDimPartitionsSpec.TARGET_ROWS_PER_SEGMENT,
String(this.targetRowsPerSegment),
);
}
if (this.maxRowsPerSegment) {
await setLabeledInput(page, 'Max rows per segment', String(this.maxRowsPerSegment));
await setLabeledInput(
page,
SingleDimPartitionsSpec.MAX_ROWS_PER_SEGMENT,
String(this.maxRowsPerSegment),
);
}
}
}

View File

@ -49,6 +49,13 @@ export async function createPage(browser: playwright.Browser): Promise<playwrigh
return page;
}
export async function getLabeledInput(page: playwright.Page, label: string): Promise<string> {
return await page.$eval(
`//*[text()="${label}"]/following-sibling::div//input`,
el => (el as HTMLInputElement).value,
);
}
export async function setLabeledInput(
page: playwright.Page,
label: string,

View File

@ -1209,12 +1209,12 @@ GROUP BY 1`;
width: ACTION_COLUMN_WIDTH,
filterable: false,
Cell: ({ value: datasource, original }) => {
const { unused, rules, compaction } = original;
const { unused, rules, compactionConfig } = original;
const datasourceActions = this.getDatasourceActions(
datasource,
unused,
rules,
compaction,
compactionConfig,
);
return (
<ActionCell