Fix bug in which Index Management data streams were being sorted incorrectly by storage size. (#86204)

They were previously being sorted alphabetically using the humanized size value. Now they're sorted numerically by the raw bytes value.
This commit is contained in:
CJ Cenizal 2020-12-17 09:52:16 -08:00 committed by GitHub
parent 5d2014dec5
commit 7bac741a1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 63 additions and 13 deletions

View file

View file

@ -20,6 +20,7 @@ export interface DataStreamsTabTestBed extends TestBed<TestSubjects> {
clickEmptyPromptIndexTemplateLink: () => void;
clickIncludeStatsSwitch: () => void;
toggleViewFilterAt: (index: number) => void;
sortTableOnStorageSize: () => void;
clickReloadButton: () => void;
clickNameAt: (index: number) => void;
clickIndicesAt: (index: number) => void;
@ -94,6 +95,14 @@ export const setup = async (overridingDependencies: any = {}): Promise<DataStrea
component.update();
};
const sortTableOnStorageSize = () => {
const { find, component } = testBed;
act(() => {
find('tableHeaderCell_storageSizeBytes_3.tableHeaderSortButton').simulate('click');
});
component.update();
};
const clickReloadButton = () => {
const { find } = testBed;
find('reloadButton').simulate('click');
@ -205,6 +214,7 @@ export const setup = async (overridingDependencies: any = {}): Promise<DataStrea
clickEmptyPromptIndexTemplateLink,
clickIncludeStatsSwitch,
toggleViewFilterAt,
sortTableOnStorageSize,
clickReloadButton,
clickNameAt,
clickIndicesAt,
@ -238,6 +248,7 @@ export const createDataStreamPayload = (dataStream: Partial<DataStream>): DataSt
health: 'green',
indexTemplateName: 'indexTemplate',
storageSize: '1b',
storageSizeBytes: 1,
maxTimeStamp: 420,
privileges: {
delete_index: true,

View file

@ -120,11 +120,21 @@ describe('Data Streams tab', () => {
createNonDataStreamIndex('non-data-stream-index'),
]);
const dataStreamForDetailPanel = createDataStreamPayload({ name: 'dataStream1' });
const dataStreamForDetailPanel = createDataStreamPayload({
name: 'dataStream1',
storageSize: '5b',
storageSizeBytes: 5,
});
setLoadDataStreamsResponse([
dataStreamForDetailPanel,
createDataStreamPayload({ name: 'dataStream2' }),
createDataStreamPayload({
name: 'dataStream2',
storageSize: '1kb',
storageSizeBytes: 1000,
}),
]);
setLoadDataStreamResponse(dataStreamForDetailPanel);
const indexTemplate = fixtures.getTemplate({ name: 'indexTemplate' });
@ -181,8 +191,28 @@ describe('Data Streams tab', () => {
// The table renders with the stats columns though.
const { tableCellsValues } = table.getMetaData('dataStreamTable');
expect(tableCellsValues).toEqual([
['', 'dataStream1', 'green', 'December 31st, 1969 7:00:00 PM', '1b', '1', 'Delete'],
['', 'dataStream2', 'green', 'December 31st, 1969 7:00:00 PM', '1b', '1', 'Delete'],
['', 'dataStream1', 'green', 'December 31st, 1969 7:00:00 PM', '5b', '1', 'Delete'],
['', 'dataStream2', 'green', 'December 31st, 1969 7:00:00 PM', '1kb', '1', 'Delete'],
]);
});
test('sorting on stats sorts by bytes value instead of human readable value', async () => {
// Guards against regression of #86122.
const { actions, table, component } = testBed;
await act(async () => {
actions.clickIncludeStatsSwitch();
});
component.update();
actions.sortTableOnStorageSize();
// The table sorts by the underlying byte values in ascending order, instead of sorting by
// the human-readable string values.
const { tableCellsValues } = table.getMetaData('dataStreamTable');
expect(tableCellsValues).toEqual([
['', 'dataStream1', 'green', 'December 31st, 1969 7:00:00 PM', '5b', '1', 'Delete'],
['', 'dataStream2', 'green', 'December 31st, 1969 7:00:00 PM', '1kb', '1', 'Delete'],
]);
});

View file

@ -16,6 +16,7 @@ export function deserializeDataStream(dataStreamFromEs: DataStreamFromEs): DataS
template,
ilm_policy: ilmPolicyName,
store_size: storageSize,
store_size_bytes: storageSizeBytes,
maximum_timestamp: maxTimeStamp,
_meta,
privileges,
@ -37,6 +38,7 @@ export function deserializeDataStream(dataStreamFromEs: DataStreamFromEs): DataS
indexTemplateName: template,
ilmPolicyName,
storageSize,
storageSizeBytes,
maxTimeStamp,
_meta,
privileges,

View file

@ -36,6 +36,7 @@ export interface DataStreamFromEs {
template: string;
ilm_policy?: string;
store_size?: string;
store_size_bytes?: number;
maximum_timestamp?: number;
privileges: PrivilegesFromEs;
hidden: boolean;
@ -57,6 +58,7 @@ export interface DataStream {
indexTemplateName: string;
ilmPolicyName?: string;
storageSize?: string;
storageSizeBytes?: number;
maxTimeStamp?: number;
_meta?: Meta;
privileges: Privileges;

View file

@ -90,12 +90,14 @@ export const DataStreamTable: React.FunctionComponent<Props> = ({
});
columns.push({
field: 'storageSize',
field: 'storageSizeBytes',
name: i18n.translate('xpack.idxMgmt.dataStreamList.table.storageSizeColumnTitle', {
defaultMessage: 'Storage size',
}),
truncateText: true,
sortable: true,
render: (storageSizeBytes: DataStream['storageSizeBytes'], dataStream: DataStream) =>
dataStream.storageSize,
});
}

View file

@ -23,6 +23,7 @@ interface PrivilegesFromEs {
interface StatsFromEs {
data_stream: string;
store_size: string;
store_size_bytes: number;
maximum_timestamp: number;
}
@ -40,7 +41,7 @@ const enhanceDataStreams = ({
if (dataStreamsStats) {
// eslint-disable-next-line @typescript-eslint/naming-convention
const { store_size, maximum_timestamp } =
const { store_size, store_size_bytes, maximum_timestamp } =
dataStreamsStats.find(
({ data_stream: statsName }: { data_stream: string }) => statsName === dataStream.name
) || {};
@ -48,6 +49,7 @@ const enhanceDataStreams = ({
enhancedDataStream = {
...enhancedDataStream,
store_size,
store_size_bytes,
maximum_timestamp,
};
}

View file

@ -52,12 +52,14 @@ export default function ({ getService }: FtrProviderContext) {
await deleteComposableIndexTemplate(name);
};
const assertDataStreamStorageSizeExists = (storageSize: string) => {
// Storage size of a document doesn't like it would be deterministic (could vary depending
const assertDataStreamStorageSizeExists = (storageSize: string, storageSizeBytes: number) => {
// Storage size of a document doesn't look like it would be deterministic (could vary depending
// on how ES, Lucene, and the file system interact), so we'll just assert its presence and
// type.
expect(storageSize).to.be.ok();
expect(typeof storageSize).to.be('string');
expect(storageSizeBytes).to.be.ok();
expect(typeof storageSizeBytes).to.be('number');
};
describe('Data streams', function () {
@ -120,10 +122,9 @@ export default function ({ getService }: FtrProviderContext) {
expect(testDataStream).to.be.ok();
// ES determines these values so we'll just echo them back.
const { name: indexName, uuid } = testDataStream!.indices[0];
const { storageSize, ...dataStreamWithoutStorageSize } = testDataStream!;
assertDataStreamStorageSizeExists(storageSize);
const { storageSize, storageSizeBytes, ...dataStreamWithoutStorageSize } = testDataStream!;
assertDataStreamStorageSizeExists(storageSize, storageSizeBytes);
expect(dataStreamWithoutStorageSize).to.eql({
name: testDataStreamName,
@ -153,8 +154,8 @@ export default function ({ getService }: FtrProviderContext) {
// ES determines these values so we'll just echo them back.
const { name: indexName, uuid } = dataStream.indices[0];
const { storageSize, ...dataStreamWithoutStorageSize } = dataStream;
assertDataStreamStorageSizeExists(storageSize);
const { storageSize, storageSizeBytes, ...dataStreamWithoutStorageSize } = dataStream;
assertDataStreamStorageSizeExists(storageSize, storageSizeBytes);
expect(dataStreamWithoutStorageSize).to.eql({
name: testDataStreamName,