Skip to content

Commit 8b82358

Browse files
[Backport 2.x] [BUG FIX] Enable Correct Sorting for Metrics in Query Insights Dashboard + dependent PRs (#200)
* Feat: dynamically display columns (#103) Signed-off-by: David Zane <[email protected]> * [Improvement] Improved Cypress test that validates the dynamic column (#168) Signed-off-by: David Zane <[email protected]> * [BUG FIX] Enable Correct Sorting for Metrics in Query Insights Dashboard (#173) Signed-off-by: David Zane <[email protected]> --------- Signed-off-by: David Zane <[email protected]> Co-authored-by: Kishore Kumaar Natarajan <[email protected]> (cherry picked from commit 7a21131) Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent f879fc6 commit 8b82358

File tree

7 files changed

+602
-409
lines changed

7 files changed

+602
-409
lines changed

cypress/e2e/1_top_queries.cy.js

Lines changed: 142 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@ import { METRICS } from '../support/constants';
1010
const indexName = 'sample_index';
1111

1212
/**
13-
Helper function to clean up the environment:
14-
- Deletes the test index.
15-
- Disables the top queries features.
13+
Helper function to clean up the environment:
14+
- Deletes the test index.
15+
- Disables the top queries features.
1616
*/
1717
const clearAll = () => {
1818
cy.deleteIndexByName(indexName);
1919
cy.disableTopQueries(METRICS.LATENCY);
2020
cy.disableTopQueries(METRICS.CPU);
2121
cy.disableTopQueries(METRICS.MEMORY);
22+
cy.disableGrouping();
2223
};
2324

2425
describe('Query Insights Dashboard', () => {
@@ -81,22 +82,6 @@ describe('Query Insights Dashboard', () => {
8182
});
8283
});
8384

84-
/**
85-
* Validate pagination works as expected
86-
*/
87-
it('should paginate the query table', () => {
88-
for (let i = 0; i < 20; i++) {
89-
cy.searchOnIndex(indexName);
90-
}
91-
// waiting for the query insights queue to drain
92-
cy.wait(10000);
93-
cy.reload();
94-
cy.get('.euiPagination').should('be.visible');
95-
cy.get('.euiPagination__item').contains('2').click();
96-
// Verify rows on the second page
97-
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
98-
});
99-
10085
it('should switch between tabs', () => {
10186
// Click Configuration tab
10287
cy.getElementByText('.euiTab', 'Configuration').click({ force: true });
@@ -119,16 +104,151 @@ describe('Query Insights Dashboard', () => {
119104
cy.get('.euiFieldSearch').type('random_string');
120105
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
121106
cy.get('.euiFieldSearch').clear();
122-
cy.get('.euiTableRow').should('have.length.greaterThan', 0); // Validate reset
107+
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
123108
});
124109

125110
it('should display a message when no top queries are found', () => {
126-
clearAll(); // disable top n queries
127-
// waiting for the query insights queue to drain
111+
clearAll();
128112
cy.wait(10000);
129113
cy.reload();
130114
cy.contains('No items found');
131115
});
132116

117+
it('should paginate the query table', () => {
118+
for (let i = 0; i < 20; i++) {
119+
cy.searchOnIndex(indexName);
120+
}
121+
cy.wait(10000);
122+
cy.reload();
123+
cy.get('.euiPagination').should('be.visible');
124+
cy.get('.euiPagination__item').contains('2').click();
125+
// Verify rows on the second page
126+
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
127+
});
133128
after(() => clearAll());
134129
});
130+
131+
describe('Query Insights Dashboard - Dynamic Columns with Stubbed Top Queries', () => {
132+
beforeEach(() => {
133+
cy.fixture('stub_top_queries.json').then((stubResponse) => {
134+
cy.intercept('GET', '**/api/top_queries/*', {
135+
statusCode: 200,
136+
body: stubResponse,
137+
}).as('getTopQueries');
138+
});
139+
140+
cy.navigateToOverview();
141+
cy.wait(1000);
142+
cy.wait('@getTopQueries');
143+
});
144+
145+
const testMetricSorting = (columnLabel, columnIndex) => {
146+
cy.get('.euiTableHeaderCell').contains(columnLabel).click();
147+
cy.wait(1000);
148+
149+
cy.get('.euiTableRow').then(($rows) => {
150+
const values = [...$rows].map(($row) => {
151+
const rawText = Cypress.$($row).find('td').eq(columnIndex).text().trim();
152+
return parseFloat(rawText.replace(/[^\d.]/g, '')); // remove 'ms'/'B'
153+
});
154+
const sortedAsc = [...values].sort((a, b) => a - b);
155+
expect(values).to.deep.equal(sortedAsc);
156+
});
157+
158+
cy.get('.euiTableHeaderCell').contains(columnLabel).click();
159+
cy.wait(1000);
160+
161+
cy.get('.euiTableRow').then(($rows) => {
162+
const values = [...$rows].map(($row) => {
163+
const rawText = Cypress.$($row).find('td').eq(columnIndex).text().trim();
164+
return parseFloat(rawText.replace(/[^\d.]/g, ''));
165+
});
166+
const sortedDesc = [...values].sort((a, b) => b - a);
167+
expect(values).to.deep.equal(sortedDesc);
168+
});
169+
};
170+
171+
it('should render only individual query-related headers when NONE filter is applied', () => {
172+
cy.wait(1000);
173+
cy.get('.euiFilterButton').contains('Type').click();
174+
cy.get('.euiFilterSelectItem').contains('query').click();
175+
cy.wait(1000);
176+
177+
const expectedHeaders = [
178+
'Id',
179+
'Type',
180+
'Timestamp',
181+
'Latency',
182+
'CPU Time',
183+
'Memory Usage',
184+
'Indices',
185+
'Search Type',
186+
'Coordinator Node ID',
187+
'Total Shards',
188+
];
189+
190+
cy.get('.euiTableHeaderCell').should('have.length', expectedHeaders.length);
191+
192+
cy.get('.euiTableHeaderCell').should(($headers) => {
193+
const actualHeaders = $headers.map((index, el) => Cypress.$(el).text().trim()).get();
194+
expect(actualHeaders).to.deep.equal(expectedHeaders);
195+
});
196+
testMetricSorting('Timestamp', 2);
197+
testMetricSorting('Latency', 3);
198+
testMetricSorting('CPU Time', 4);
199+
testMetricSorting('Memory Usage', 5);
200+
});
201+
202+
it('should render only group-related headers in the correct order when SIMILARITY filter is applied', () => {
203+
cy.get('.euiFilterButton').contains('Type').click();
204+
cy.get('.euiFilterSelectItem').contains('group').click();
205+
cy.wait(1000);
206+
207+
const expectedHeaders = [
208+
'Id',
209+
'Type',
210+
'Query Count',
211+
'Average Latency',
212+
'Average CPU Time',
213+
'Average Memory Usage',
214+
];
215+
216+
cy.get('.euiTableHeaderCell').should(($headers) => {
217+
const actualHeaders = $headers.map((index, el) => Cypress.$(el).text().trim()).get();
218+
expect(actualHeaders).to.deep.equal(expectedHeaders);
219+
});
220+
testMetricSorting('Query Count', 2);
221+
testMetricSorting('Average Latency', 3);
222+
testMetricSorting('Average CPU Time', 4);
223+
testMetricSorting('Average Memory Usage', 5);
224+
});
225+
it('should display both query and group data with proper headers when both are selected', () => {
226+
cy.get('.euiFilterButton').contains('Type').click();
227+
cy.get('.euiFilterSelectItem').contains('query').click();
228+
cy.get('.euiFilterSelectItem').contains('group').click();
229+
cy.wait(1000);
230+
231+
const expectedGroupHeaders = [
232+
'Id',
233+
'Type',
234+
'Query Count',
235+
'Timestamp',
236+
'Avg Latency / Latency',
237+
'Avg CPU Time / CPU Time',
238+
'Avg Memory Usage / Memory Usage',
239+
'Indices',
240+
'Search Type',
241+
'Coordinator Node ID',
242+
'Total Shards',
243+
];
244+
cy.get('.euiTableHeaderCell').should(($headers) => {
245+
const actualHeaders = $headers.map((index, el) => Cypress.$(el).text().trim()).get();
246+
expect(actualHeaders).to.deep.equal(expectedGroupHeaders);
247+
});
248+
testMetricSorting('Query Count', 2);
249+
testMetricSorting('Timestamp', 3);
250+
testMetricSorting('Avg Latency / Latency', 4);
251+
testMetricSorting('Avg CPU Time / CPU Time', 5);
252+
testMetricSorting('Avg Memory Usage / Memory Usage', 6);
253+
});
254+
});
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
{
2+
"ok": true,
3+
"response": {
4+
"top_queries": [
5+
{
6+
"timestamp": 1713934974000,
7+
"id": "a2e1c822-3e3c-4d1b-adb2-9f73af094b43",
8+
"search_type": "query_then_fetch",
9+
"indices": ["my-index"],
10+
"node_id": "UYKFun8PSAeJvkkt9cWf0w",
11+
"group_by": "NONE",
12+
"total_shards": 1,
13+
"labels": {
14+
"X-Opaque-Id": "90eb5c3b-8448-4af3-84ce-a941eee9ed5f"
15+
},
16+
"measurements": {
17+
"cpu": { "number": 1340000, "count": 1, "aggregationType": "NONE" },
18+
"latency": { "number": 22, "count": 1, "aggregationType": "NONE" },
19+
"memory": { "number": 204800, "count": 1, "aggregationType": "NONE" }
20+
}
21+
},
22+
{
23+
"timestamp": 1713934989000,
24+
"id": "130a5d36-615e-43e8-ad99-e1b90d527f44",
25+
"search_type": "query_then_fetch",
26+
"indices": [".kibana"],
27+
"node_id": "UYKFun8PSAeJvkkt9cWf0w",
28+
"group_by": "SIMILARITY",
29+
"total_shards": 1,
30+
"labels": {},
31+
"query_group_hashcode": "2219a4bb71bd0d262e6d0f5504b88537",
32+
"measurements": {
33+
"memory": { "number": 58000, "count": 1, "aggregationType": "AVERAGE" },
34+
"cpu": { "number": 1780000, "count": 1, "aggregationType": "AVERAGE" },
35+
"latency": { "number": 10, "count": 1, "aggregationType": "AVERAGE" }
36+
}
37+
},
38+
{
39+
"timestamp": 1713935004000,
40+
"id": "a2e1c822-3e3c-4d1b-adb2-9f73af094b43",
41+
"search_type": "query_then_fetch",
42+
"indices": ["my-index"],
43+
"node_id": "UYKFun8PSAeJvkkt9cWf0w",
44+
"group_by": "NONE",
45+
"total_shards": 1,
46+
"labels": {
47+
"X-Opaque-Id": "90eb5c3b-8448-4af3-84ce-a941eee9ed5f"
48+
},
49+
"measurements": {
50+
"memory": { "number": 170320, "count": 1, "aggregationType": "NONE" },
51+
"cpu": { "number": 2100000, "count": 1, "aggregationType": "NONE" },
52+
"latency": { "number": 13, "count": 1, "aggregationType": "NONE" }
53+
}
54+
},
55+
{
56+
"timestamp": 1713935019000,
57+
"id": "7cd4c7f1-3803-4c5e-a41c-258e04f96f78",
58+
"search_type": "query_then_fetch",
59+
"indices": ["my-index"],
60+
"node_id": "UYKFun8PSAeJvkkt9cWf0w",
61+
"group_by": "NONE",
62+
"total_shards": 1,
63+
"labels": {
64+
"X-Opaque-Id": "8a936346-8d19-409c-9fe6-8b890eca1f7c"
65+
},
66+
"measurements": {
67+
"cpu": { "number": 990000, "count": 1, "aggregationType": "NONE" },
68+
"latency": { "number": 18, "count": 1, "aggregationType": "NONE" },
69+
"memory": { "number": 81200, "count": 1, "aggregationType": "NONE" }
70+
}
71+
},
72+
{
73+
"timestamp": 1713935033000,
74+
"id": "76f5e51f-33f6-480c-8b20-8003abb93d19",
75+
"search_type": "query_then_fetch",
76+
"indices": [".kibana"],
77+
"node_id": "UYKFun8PSAeJvkkt9cWf0w",
78+
"group_by": "SIMILARITY",
79+
"total_shards": 1,
80+
"labels": {
81+
"X-Opaque-Id": "660baeb1-077b-4884-8bae-890cfe30e776"
82+
},
83+
"query_group_hashcode": "a336f9580d5d980f7403f6d179f454eb",
84+
"measurements": {
85+
"memory": { "number": 133600, "count": 1, "aggregationType": "AVERAGE" },
86+
"cpu": { "number": 990000, "count": 1, "aggregationType": "AVERAGE" },
87+
"latency": { "number": 9, "count": 1, "aggregationType": "AVERAGE" }
88+
}
89+
},
90+
{
91+
"timestamp": 1713935048000,
92+
"id": "37d633a7-20e6-41a1-96e9-cd4806511dbf",
93+
"search_type": "query_then_fetch",
94+
"indices": [".kibana"],
95+
"node_id": "UYKFun8PSAeJvkkt9cWf0w",
96+
"group_by": "SIMILARITY",
97+
"total_shards": 1,
98+
"labels": {},
99+
"query_group_hashcode": "7cef9a399c117a0278025a89e943eebc",
100+
"measurements": {
101+
"memory": { "number": 640320, "count": 3, "aggregationType": "AVERAGE" },
102+
"cpu": { "number": 3190000, "count": 3, "aggregationType": "AVERAGE" },
103+
"latency": { "number": 6, "count": 1, "aggregationType": "NONE" }
104+
}
105+
},
106+
{
107+
"timestamp": 1713935062000,
108+
"id": "9982b7fc-0339-47d8-b77f-8de1bda76b72",
109+
"search_type": "query_then_fetch",
110+
"indices": [".kibana"],
111+
"node_id": "UYKFun8PSAeJvkkt9cWf0w",
112+
"group_by": "SIMILARITY",
113+
"total_shards": 1,
114+
"labels": {},
115+
"query_group_hashcode": "7cef9a399c117a0278025a89e943eebc",
116+
"measurements": {
117+
"memory": { "number": 812400, "count": 4, "aggregationType": "AVERAGE" },
118+
"cpu": { "number": 2280000, "count": 4, "aggregationType": "AVERAGE" },
119+
"latency": { "number": 4, "count": 4, "aggregationType": "AVERAGE" }
120+
}
121+
},
122+
{
123+
"timestamp": 1713935078000,
124+
"id": "d8dccf54-8dcb-4411-9fd6-977844be8fb3",
125+
"search_type": "query_then_fetch",
126+
"indices": [".kibana"],
127+
"node_id": "UYKFun8PSAeJvkkt9cWf0w",
128+
"group_by": "SIMILARITY",
129+
"total_shards": 1,
130+
"labels": {},
131+
"query_group_hashcode": "2219a4bb71bd0d262e6d0f5504b88537",
132+
"measurements": {
133+
"memory": { "number": 59000, "count": 1, "aggregationType": "AVERAGE" },
134+
"cpu": { "number": 1720000, "count": 1, "aggregationType": "AVERAGE" },
135+
"latency": { "number": 11, "count": 1, "aggregationType": "NONE" }
136+
}
137+
}
138+
]
139+
}
140+
}

cypress/support/commands.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,20 @@ Cypress.Commands.add('disableGrouping', () => {
138138
failOnStatusCode: true,
139139
});
140140
});
141+
Cypress.Commands.add('setWindowSize', (size = '1m') => {
142+
cy.request({
143+
method: 'PUT',
144+
url: `${Cypress.env('openSearchUrl')}/_cluster/settings`,
145+
body: {
146+
persistent: {
147+
'search.insights.top_queries.latency.window_size': size,
148+
'search.insights.top_queries.cpu.window_size': size,
149+
'search.insights.top_queries.memory.window_size': size,
150+
},
151+
},
152+
failOnStatusCode: true,
153+
});
154+
});
141155

142156
Cypress.Commands.add('createIndexByName', (indexName, body = {}) => {
143157
cy.request('POST', `${Cypress.env('openSearchUrl')}/${indexName}/_doc`, body);

public/components/__snapshots__/app.test.tsx.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ exports[`<QueryInsightsDashboardsApp /> spec renders the component 1`] = `
520520
aria-live="polite"
521521
aria-sort="none"
522522
class="euiTableHeaderCell"
523-
data-test-subj="tableHeaderCell_measurements_2"
523+
data-test-subj="tableHeaderCell_Query Count_2"
524524
role="columnheader"
525525
scope="col"
526526
>
@@ -570,7 +570,7 @@ exports[`<QueryInsightsDashboardsApp /> spec renders the component 1`] = `
570570
aria-live="polite"
571571
aria-sort="none"
572572
class="euiTableHeaderCell"
573-
data-test-subj="tableHeaderCell_measurements.latency_4"
573+
data-test-subj="tableHeaderCell_Latency_4"
574574
role="columnheader"
575575
scope="col"
576576
>
@@ -595,7 +595,7 @@ exports[`<QueryInsightsDashboardsApp /> spec renders the component 1`] = `
595595
aria-live="polite"
596596
aria-sort="none"
597597
class="euiTableHeaderCell"
598-
data-test-subj="tableHeaderCell_measurements.cpu_5"
598+
data-test-subj="tableHeaderCell_CPU Time_5"
599599
role="columnheader"
600600
scope="col"
601601
>
@@ -620,7 +620,7 @@ exports[`<QueryInsightsDashboardsApp /> spec renders the component 1`] = `
620620
aria-live="polite"
621621
aria-sort="none"
622622
class="euiTableHeaderCell"
623-
data-test-subj="tableHeaderCell_measurements.memory_6"
623+
data-test-subj="tableHeaderCell_Memory Usage_6"
624624
role="columnheader"
625625
scope="col"
626626
>

0 commit comments

Comments
 (0)