Logs: update tests

This commit is contained in:
L2D2Grafana
2026-01-07 07:50:55 -08:00
parent fa9cc6bc8c
commit ddfca17d92
@@ -6,6 +6,7 @@ import {
mergeWithDefaults,
hasLegacyColumns,
extractColumnsValue,
extractDisplayedFields,
migrateLegacyColumns,
} from './columnMigration';
@@ -186,104 +187,128 @@ describe('columnMigration', () => {
});
});
describe('extractDisplayedFields', () => {
it('should extract displayedFields array', () => {
const state = { displayedFields: ['Time', 'level', 'host'] };
expect(extractDisplayedFields(state)).toEqual(['Time', 'level', 'host']);
});
it('should return undefined when displayedFields not present', () => {
const state = { columns: ['Time'] };
expect(extractDisplayedFields(state)).toBeUndefined();
});
it('should extract empty displayedFields array', () => {
const state = { displayedFields: [] };
expect(extractDisplayedFields(state)).toEqual([]);
});
it('should handle state with both columns and displayedFields', () => {
const state = {
columns: { '0': 'cluster', '1': 'Line' },
displayedFields: ['service_name', 'component'],
};
expect(extractDisplayedFields(state)).toEqual(['service_name', 'component']);
});
});
describe('migrateLegacyColumns', () => {
const defaultDisplayedFields = ['Time', LOG_LINE_BODY_FIELD_NAME];
it('should return null when logsState is null', () => {
expect(migrateLegacyColumns(null, defaultDisplayedFields)).toBeNull();
describe('general behavior', () => {
it('should return null when logsState is null', () => {
expect(migrateLegacyColumns(null, defaultDisplayedFields, 'table')).toBeNull();
});
it('should return null when logsState is undefined', () => {
expect(migrateLegacyColumns(undefined, defaultDisplayedFields, 'table')).toBeNull();
});
it('should return null when no columns property exists', () => {
const logsState = { displayedFields: ['Time'] };
expect(migrateLegacyColumns(logsState, defaultDisplayedFields, 'table')).toBeNull();
});
it('should return null when visualisationType is not provided', () => {
const logsState = { columns: ['Time', 'level'] };
expect(migrateLegacyColumns(logsState, defaultDisplayedFields)).toBeNull();
});
it('should return null when visualisationType is unknown', () => {
const logsState = { columns: ['Time', 'level'] };
expect(migrateLegacyColumns(logsState, defaultDisplayedFields, 'unknown')).toBeNull();
});
});
it('should return null when logsState is undefined', () => {
expect(migrateLegacyColumns(undefined, defaultDisplayedFields)).toBeNull();
});
describe('visualisationType: table', () => {
it('should return null when columns is empty array', () => {
const logsState = { columns: [] };
expect(migrateLegacyColumns(logsState, defaultDisplayedFields, 'table')).toBeNull();
});
it('should return null when no columns property exists', () => {
const logsState = { displayedFields: ['Time'] };
expect(migrateLegacyColumns(logsState, defaultDisplayedFields)).toBeNull();
});
it('should return null when columns is invalid', () => {
const logsState = { columns: 'invalid' };
expect(migrateLegacyColumns(logsState, defaultDisplayedFields, 'table')).toBeNull();
});
it('should return null when columns is empty array', () => {
const logsState = { columns: [] };
expect(migrateLegacyColumns(logsState, defaultDisplayedFields)).toBeNull();
});
it('should migrate array format columns', () => {
const logsState = { columns: ['Time', TABLE_LINE_FIELD_NAME, 'level'] };
const result = migrateLegacyColumns(logsState, defaultDisplayedFields, 'table');
expect(result).toEqual(['Time', LOG_LINE_BODY_FIELD_NAME, 'level']);
});
it('should return null when columns is invalid', () => {
const logsState = { columns: 'invalid' };
expect(migrateLegacyColumns(logsState, defaultDisplayedFields)).toBeNull();
});
it('should migrate object format columns', () => {
const logsState = { columns: { 0: 'Time', 1: TABLE_LINE_FIELD_NAME, 2: 'level' } };
const result = migrateLegacyColumns(logsState, defaultDisplayedFields, 'table');
expect(result).toEqual(['Time', LOG_LINE_BODY_FIELD_NAME, 'level']);
});
it('should migrate array format columns', () => {
const logsState = { columns: ['Time', TABLE_LINE_FIELD_NAME, 'level'] };
const result = migrateLegacyColumns(logsState, defaultDisplayedFields);
expect(result).toEqual(['Time', LOG_LINE_BODY_FIELD_NAME, 'level']);
});
it('should return only mapped columns without merging with defaults', () => {
const logsState = { columns: ['level', 'host'] };
const result = migrateLegacyColumns(logsState, defaultDisplayedFields, 'table');
// Table visualization returns only the columns, not merged with defaults
expect(result).toEqual(['level', 'host']);
});
it('should migrate object format columns', () => {
const logsState = { columns: { 0: 'Time', 1: TABLE_LINE_FIELD_NAME, 2: 'level' } };
const result = migrateLegacyColumns(logsState, defaultDisplayedFields);
expect(result).toEqual(['Time', LOG_LINE_BODY_FIELD_NAME, 'level']);
});
it('should map Line to body field name', () => {
const logsState = { columns: [TABLE_LINE_FIELD_NAME] };
const result = migrateLegacyColumns(logsState, defaultDisplayedFields, 'table');
expect(result).toEqual([LOG_LINE_BODY_FIELD_NAME]);
});
it('should merge with defaults and avoid duplicates', () => {
const logsState = { columns: ['level', 'host'] };
const result = migrateLegacyColumns(logsState, defaultDisplayedFields);
expect(result).toEqual(['Time', LOG_LINE_BODY_FIELD_NAME, 'level', 'host']);
});
it('should map timestamp to Time', () => {
const logsState = { columns: ['timestamp', 'level'] };
const result = migrateLegacyColumns(logsState, defaultDisplayedFields, 'table');
expect(result).toEqual(['Time', 'level']);
});
it('should handle columns that are already in defaults', () => {
const logsState = { columns: ['Time', 'level'] };
const result = migrateLegacyColumns(logsState, defaultDisplayedFields);
expect(result).toEqual(['Time', LOG_LINE_BODY_FIELD_NAME, 'level']);
});
it('should map body to LOG_LINE_BODY_FIELD_NAME', () => {
const logsState = { columns: ['body', 'level'] };
const result = migrateLegacyColumns(logsState, defaultDisplayedFields, 'table');
expect(result).toEqual([LOG_LINE_BODY_FIELD_NAME, 'level']);
});
it('should map Line to body and merge correctly', () => {
const logsState = { columns: [TABLE_LINE_FIELD_NAME] };
const result = migrateLegacyColumns(logsState, defaultDisplayedFields);
// Line maps to LOG_LINE_BODY_FIELD_NAME which is already in defaults
expect(result).toEqual(['Time', LOG_LINE_BODY_FIELD_NAME]);
});
it('should ignore displayedFields and only use columns for table', () => {
const logsState = {
columns: ['level'],
displayedFields: ['existing', 'fields'],
};
const result = migrateLegacyColumns(logsState, defaultDisplayedFields, 'table');
// Should only return mapped columns, ignoring displayedFields
expect(result).toEqual(['level']);
});
it('should handle empty defaults', () => {
const logsState = { columns: ['Time', TABLE_LINE_FIELD_NAME] };
const result = migrateLegacyColumns(logsState, []);
expect(result).toEqual(['Time', LOG_LINE_BODY_FIELD_NAME]);
});
it('should preserve other logsState properties conceptually', () => {
// This test verifies the function only looks at columns
const logsState = {
columns: ['level'],
visualisationType: 'table',
displayedFields: ['existing'],
};
const result = migrateLegacyColumns(logsState, defaultDisplayedFields);
expect(result).toEqual(['Time', LOG_LINE_BODY_FIELD_NAME, 'level']);
});
it('should handle real URL format with full logsState structure', () => {
// Real format from URL: columns%22:%7B%220%22:%22cluster%22,%221%22:%22Line%22,%222%22:%22Time%22%7D
// Full structure: {"columns":{"0":"cluster","1":"Line","2":"Time"},"visualisationType":"table","labelFieldName":"labels","refId":"A"}
const logsState = {
columns: { '0': 'cluster', '1': 'Line', '2': 'Time' },
visualisationType: 'table',
labelFieldName: 'labels',
refId: 'A',
};
const result = migrateLegacyColumns(logsState, defaultDisplayedFields);
// cluster is new, Line maps to body (already in defaults), Time is already in defaults
expect(result).toEqual(['Time', LOG_LINE_BODY_FIELD_NAME, 'cluster']);
});
describe('real URL format from ops.grafana-ops.net', () => {
// URL: https://ops.grafana-ops.net/explore?schemaVersion=1&panes=%7B%2259n%22:...
// Decoded panelsState.logs:
// {
// "sortOrder": "Ascending",
// "columns": {"0": "cluster", "1": "Line", "2": "Time"},
// "visualisationType": "table",
// "labelFieldName": "labels",
// "refId": "A"
// }
it('should handle real URL format with full logsState structure', () => {
const logsState = {
columns: { '0': 'cluster', '1': 'Line', '2': 'Time' },
visualisationType: 'table',
labelFieldName: 'labels',
refId: 'A',
};
const result = migrateLegacyColumns(logsState, defaultDisplayedFields, 'table');
// Returns mapped columns in order (Line -> LOG_LINE_BODY_FIELD_NAME)
expect(result).toEqual(['cluster', LOG_LINE_BODY_FIELD_NAME, 'Time']);
});
it('should migrate columns from real Grafana Explore URL', () => {
const logsState = {
@@ -293,51 +318,62 @@ describe('columnMigration', () => {
labelFieldName: 'labels',
refId: 'A',
};
const result = migrateLegacyColumns(logsState, defaultDisplayedFields);
const result = migrateLegacyColumns(logsState, defaultDisplayedFields, 'table');
expect(result).toContain('cluster');
expect(result).toContain(LOG_LINE_BODY_FIELD_NAME);
expect(result).toContain('Time');
expect(result).not.toContain('Line'); // Line should be mapped
});
it('should map Line to body field name', () => {
it('should map legacy field names correctly', () => {
const logsState = {
columns: { '0': 'timestamp', '1': 'body', '2': 'env', '3': 'namespace' },
};
const result = migrateLegacyColumns(logsState, defaultDisplayedFields, 'table');
expect(result).toEqual(['Time', LOG_LINE_BODY_FIELD_NAME, 'env', 'namespace']);
});
});
describe('visualisationType: logs', () => {
it('should return null when no columns property exists (required for migration)', () => {
const logsState = { displayedFields: ['Time', 'level'] };
// logs visualization requires legacy columns to exist for migration to run
expect(migrateLegacyColumns(logsState, defaultDisplayedFields, 'logs')).toBeNull();
});
it('should return displayedFields directly when columns exist', () => {
const logsState = {
columns: { '0': 'old', '1': 'columns' }, // Legacy columns must exist
displayedFields: ['Time', 'level', 'host'],
};
const result = migrateLegacyColumns(logsState, defaultDisplayedFields, 'logs');
expect(result).toEqual(['Time', 'level', 'host']);
});
it('should return null when displayedFields is empty', () => {
const logsState = {
columns: { '0': 'old' },
displayedFields: [],
};
expect(migrateLegacyColumns(logsState, defaultDisplayedFields, 'logs')).toBeNull();
});
it('should return null when displayedFields is not an array', () => {
const logsState = {
columns: { '0': 'old' },
displayedFields: 'not-an-array',
};
expect(migrateLegacyColumns(logsState, defaultDisplayedFields, 'logs')).toBeNull();
});
it('should ignore columns and use displayedFields for logs visualization', () => {
const logsState = {
sortOrder: 'Ascending',
columns: { '0': 'cluster', '1': 'Line', '2': 'Time' },
visualisationType: 'table',
labelFieldName: 'labels',
refId: 'A',
displayedFields: ['service_name', 'component'],
};
const result = migrateLegacyColumns(logsState, defaultDisplayedFields);
// Line should be mapped to LOG_LINE_BODY_FIELD_NAME, not remain as 'Line'
expect(result).not.toContain('Line');
expect(result).toContain(LOG_LINE_BODY_FIELD_NAME);
});
it('should place defaults first, then additional columns', () => {
const logsState = {
sortOrder: 'Ascending',
columns: { '0': 'cluster', '1': 'Line', '2': 'Time' },
visualisationType: 'table',
labelFieldName: 'labels',
refId: 'A',
};
const result = migrateLegacyColumns(logsState, defaultDisplayedFields);
// Default fields (Time, body) should come first
expect(result![0]).toBe('Time');
expect(result![1]).toBe(LOG_LINE_BODY_FIELD_NAME);
// Then additional fields from columns (cluster)
expect(result![2]).toBe('cluster');
});
it('should not duplicate fields that exist in both defaults and columns', () => {
const logsState = {
columns: { '0': 'Time', '1': 'Line', '2': 'cluster' },
visualisationType: 'table',
};
const result = migrateLegacyColumns(logsState, defaultDisplayedFields);
// Should not have duplicate Time or body entries
expect(result!.filter((f) => f === 'Time').length).toBe(1);
expect(result!.filter((f) => f === LOG_LINE_BODY_FIELD_NAME).length).toBe(1);
const result = migrateLegacyColumns(logsState, defaultDisplayedFields, 'logs');
// Should return displayedFields, ignoring columns
expect(result).toEqual(['service_name', 'component']);
});
});
});