Skip to content

Commit a800ac4

Browse files
opensearch-trigger-bot[bot]github-actions[bot]Kishore Kumaar Natarajan
authored
[Feature] Fetch top query with verbose=false on overview (#164) (#175)
* Fetch top query with verbose=false * Fetch top query with verbose=false * Updated the queryInsightPlugin.ts * Updated the queryInsightPlugin.ts * Updated the queryInsightPlugin.ts * Disabling failing Cypress usecase * Updated tests * Updated tests * Updated tests * Update 1_top_queries.cy.js * Updated tests * Updated tests * Updated tests --------- (cherry picked from commit 3e9f577) Signed-off-by: Kishore Kumaar Natarajan <[email protected]> Signed-off-by: Kishore Kumaar Natarajan <[email protected]> Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Kishore Kumaar Natarajan <[email protected]>
1 parent 67dd523 commit a800ac4

File tree

12 files changed

+241
-30
lines changed

12 files changed

+241
-30
lines changed

common/utils/QueryUtils.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ export const retrieveQueryById = async (
1111
dataSourceId: string,
1212
start: string | null,
1313
end: string | null,
14-
id: string | null
14+
id: string | null,
15+
verbose: boolean
1516
): Promise<SearchQueryRecord | null> => {
1617
const nullResponse = { response: { top_queries: [] } };
1718
const params = {
@@ -20,6 +21,7 @@ export const retrieveQueryById = async (
2021
from: start,
2122
to: end,
2223
id,
24+
verbose,
2325
},
2426
};
2527

cypress/e2e/1_top_queries.cy.js

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,69 @@ describe('Query Insights Dashboard', () => {
125125
// Verify rows on the second page
126126
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
127127
});
128-
after(() => clearAll());
128+
129+
it('should get minimal details of the query using verbose=false', () => {
130+
const to = new Date().toISOString();
131+
const from = new Date(Date.now() - 60 * 60 * 1000).toISOString();
132+
133+
return cy
134+
.request({
135+
method: 'GET',
136+
url: `/api/top_queries/latency`,
137+
qs: {
138+
from: from,
139+
to: to,
140+
verbose: false,
141+
},
142+
})
143+
.then((response) => {
144+
expect(response.status).to.eq(200);
145+
expect(response.body).to.have.property('ok', true);
146+
147+
const responseData = response.body.response;
148+
expect(responseData).to.have.property('top_queries');
149+
expect(responseData.top_queries).to.be.an('array');
150+
expect(responseData.top_queries.length).to.be.greaterThan(0);
151+
152+
const firstQuery = responseData.top_queries[0];
153+
const requiredFields = [
154+
'group_by',
155+
'id',
156+
'indices',
157+
'labels',
158+
'measurements',
159+
'node_id',
160+
'search_type',
161+
'timestamp',
162+
'total_shards',
163+
];
164+
165+
expect(firstQuery).to.include.all.keys(requiredFields);
166+
const typeValidations = {
167+
group_by: 'string',
168+
id: 'string',
169+
indices: 'array',
170+
labels: 'object',
171+
measurements: 'object',
172+
node_id: 'string',
173+
search_type: 'string',
174+
timestamp: 'number',
175+
total_shards: 'number',
176+
};
177+
Object.entries(typeValidations).forEach(([field, type]) => {
178+
expect(firstQuery[field]).to.be.a(type, `${field} should be a ${type}`);
179+
});
180+
expect(firstQuery.measurements).to.have.all.keys(['cpu', 'latency', 'memory']);
181+
['cpu', 'latency', 'memory'].forEach((metric) => {
182+
expect(firstQuery.measurements[metric]).to.be.an('object');
183+
});
184+
});
185+
186+
after(() => clearAll());
187+
});
129188
});
130189

131-
describe('Query Insights Dashboard - Dynamic Columns with Stubbed Top Queries', () => {
190+
describe('Query Insights Dashboard - Dynamic Columns change with Intercepted Top Queries', () => {
132191
beforeEach(() => {
133192
cy.fixture('stub_top_queries.json').then((stubResponse) => {
134193
cy.intercept('GET', '**/api/top_queries/*', {

cypress/e2e/2_query_details.cy.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,5 +133,52 @@ describe('Top Queries Details Page', () => {
133133
cy.get('#latency').trigger('mousemove', { clientX: 100, clientY: 100 });
134134
});
135135

136+
it('should get complete details of the query using verbose=true for query type', () => {
137+
const to = new Date().toISOString();
138+
const from = new Date(Date.now() - 60 * 60 * 1000).toISOString();
139+
140+
return cy
141+
.request({
142+
method: 'GET',
143+
url: `/api/top_queries/latency`,
144+
qs: {
145+
from: from,
146+
to: to,
147+
verbose: true,
148+
},
149+
})
150+
.then((response) => {
151+
expect(response.status).to.eq(200);
152+
expect(response.body).to.have.property('ok', true);
153+
154+
cy.log('Response structure:', JSON.stringify(response.body, null, 2));
155+
156+
const responseData = response.body.response;
157+
expect(responseData).to.have.property('top_queries');
158+
expect(responseData.top_queries).to.be.an('array');
159+
expect(responseData.top_queries.length).to.be.greaterThan(0);
160+
161+
const firstQuery = responseData.top_queries[0];
162+
expect(firstQuery).to.include.all.keys([
163+
'group_by',
164+
'id',
165+
'indices',
166+
'labels',
167+
'measurements',
168+
'node_id',
169+
'phase_latency_map',
170+
'search_type',
171+
'source',
172+
'task_resource_usages',
173+
'timestamp',
174+
'total_shards',
175+
]);
176+
177+
expect(firstQuery.group_by).to.equal('NONE');
178+
expect(firstQuery.indices).to.be.an('array');
179+
expect(firstQuery.measurements).to.have.all.keys(['cpu', 'latency', 'memory']);
180+
});
181+
});
182+
136183
after(() => clearAll());
137184
});

cypress/e2e/4_group_details.cy.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,62 @@ describe('Query Group Details Page', () => {
106106
cy.get('#latency').should('be.visible');
107107
});
108108
});
109+
it('should get complete details of the query using verbose=true for group type', () => {
110+
const to = new Date().toISOString();
111+
const from = new Date(Date.now() - 60 * 60 * 1000).toISOString();
112+
113+
return cy
114+
.request({
115+
method: 'GET',
116+
url: `/api/top_queries/latency`,
117+
qs: {
118+
from: from,
119+
to: to,
120+
verbose: true,
121+
},
122+
})
123+
.then((response) => {
124+
// Verify response status and structure
125+
expect(response.status).to.eq(200);
126+
expect(response.body).to.have.property('ok', true);
127+
128+
cy.log('Response structure:', JSON.stringify(response.body, null, 2));
129+
130+
const responseData = response.body.response;
131+
expect(responseData).to.have.property('top_queries');
132+
expect(responseData.top_queries).to.be.an('array');
133+
expect(responseData.top_queries.length).to.be.greaterThan(0);
134+
135+
const firstQuery = responseData.top_queries[0];
136+
expect(firstQuery).to.include.all.keys([
137+
'group_by',
138+
'id',
139+
'indices',
140+
'labels',
141+
'measurements',
142+
'node_id',
143+
'phase_latency_map',
144+
'query_group_hashcode',
145+
'search_type',
146+
'source',
147+
'task_resource_usages',
148+
'timestamp',
149+
'total_shards',
150+
]);
151+
expect(firstQuery.group_by).to.equal('SIMILARITY');
152+
expect(firstQuery.indices).to.be.an('array');
153+
expect(firstQuery.id).to.be.a('string');
154+
expect(firstQuery.labels).to.be.an('object');
155+
expect(firstQuery.node_id).to.be.a('string');
156+
expect(firstQuery.query_group_hashcode).to.be.a('string');
157+
expect(firstQuery.search_type).to.be.a('string');
158+
expect(firstQuery.timestamp).to.be.a('number');
159+
expect(firstQuery.total_shards).to.be.a('number');
160+
expect(firstQuery.measurements.cpu).to.be.an('object');
161+
expect(firstQuery.measurements.latency).to.be.an('object');
162+
expect(firstQuery.measurements.memory).to.be.an('object');
163+
});
164+
});
109165

110166
after(() => clearAll());
111167
});

public/pages/QueryDetails/QueryDetails.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ describe('QueryDetails component', () => {
5858
initialEntries={[
5959
`/query-details/?id=${hash(
6060
mockQuery.id
61-
)}&from=2025-01-21T22:30:33.347Z&to=2025-01-22T22:30:33.347Z`,
61+
)}&from=2025-01-21T22:30:33.347Z&to=2025-01-22T22:30:33.347Z&verbose=true`,
6262
]}
6363
>
6464
<DataSourceContext.Provider value={mockDataSourceContext}>

public/pages/QueryDetails/QueryDetails.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const QueryDetails = ({
4747
const id = searchParams.get('id');
4848
const from = searchParams.get('from');
4949
const to = searchParams.get('to');
50+
const verbose = Boolean(searchParams.get('verbose'));
5051

5152
const [query, setQuery] = useState<SearchQueryRecord | null>(null);
5253
const history = useHistory();
@@ -60,15 +61,22 @@ const QueryDetails = ({
6061
}, []);
6162

6263
const fetchQueryDetails = async () => {
63-
const retrievedQuery = await retrieveQueryById(core, getDataSourceFromUrl().id, from, to, id);
64+
const retrievedQuery = await retrieveQueryById(
65+
core,
66+
getDataSourceFromUrl().id,
67+
from,
68+
to,
69+
id,
70+
verbose
71+
);
6472
setQuery(retrievedQuery);
6573
};
6674

6775
useEffect(() => {
68-
if (id && from && to) {
76+
if (id && from && to && verbose != null) {
6977
fetchQueryDetails();
7078
}
71-
}, [id, from, to]);
79+
}, [id, from, to, verbose]);
7280

7381
// Initialize the Plotly chart
7482
const initPlotlyChart = useCallback(() => {

public/pages/QueryGroupDetails/QueryGroupDetails.test.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ describe('QueryGroupDetails', () => {
6262
const renderComponent = () => {
6363
return render(
6464
<MemoryRouter
65-
initialEntries={['/query-group-details?id=mockId&from=1632441600000&to=1632528000000']}
65+
initialEntries={[
66+
'/query-group-details?id=mockId&from=1632441600000&to=1632528000000&verbose=true',
67+
]}
6668
>
6769
<DataSourceContext.Provider value={mockDataSourceContext}>
6870
<Route path="/query-group-details">
@@ -101,7 +103,8 @@ describe('QueryGroupDetails', () => {
101103
undefined,
102104
'1632441600000',
103105
'1632528000000',
104-
'mockId'
106+
'mockId',
107+
true
105108
);
106109
});
107110

public/pages/QueryGroupDetails/QueryGroupDetails.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export const QueryGroupDetails = ({
4949
const id = searchParams.get('id');
5050
const from = searchParams.get('from');
5151
const to = searchParams.get('to');
52+
const verbose = Boolean(searchParams.get('verbose'));
5253

5354
const [query, setQuery] = useState<SearchQueryRecord | null>(null);
5455
const { dataSource, setDataSource } = useContext(DataSourceContext)!;
@@ -62,15 +63,22 @@ export const QueryGroupDetails = ({
6263
const history = useHistory();
6364

6465
const fetchQueryDetails = async () => {
65-
const retrievedQuery = await retrieveQueryById(core, getDataSourceFromUrl().id, from, to, id);
66+
const retrievedQuery = await retrieveQueryById(
67+
core,
68+
getDataSourceFromUrl().id,
69+
from,
70+
to,
71+
id,
72+
verbose
73+
);
6674
setQuery(retrievedQuery);
6775
};
6876

6977
useEffect(() => {
70-
if (id && from && to) {
78+
if (id && from && to && verbose) {
7179
fetchQueryDetails();
7280
}
73-
}, [id, from, to]);
81+
}, [id, from, to, verbose]);
7482

7583
useEffect(() => {
7684
if (query) {

public/pages/QueryInsights/QueryInsights.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ const QueryInsights = ({
117117
onClick={() => {
118118
const route =
119119
query.group_by === 'SIMILARITY'
120-
? `/query-group-details?from=${from}&to=${to}&id=${query.id}`
121-
: `/query-details?from=${from}&to=${to}&id=${query.id}`;
120+
? `/query-group-details?from=${from}&to=${to}&id=${query.id}&verbose=${true}`
121+
: `/query-details?from=${from}&to=${to}&id=${query.id}&verbose=${true}`;
122122
history.push(route);
123123
}}
124124
>
@@ -139,8 +139,8 @@ const QueryInsights = ({
139139
onClick={() => {
140140
const route =
141141
query.group_by === 'SIMILARITY'
142-
? `/query-group-details?from=${from}&to=${to}&id=${query.id}`
143-
: `/query-details?from=${from}&to=${to}&id=${query.id}`;
142+
? `/query-group-details?from=${from}&to=${to}&id=${query.id}&verbose=${true}`
143+
: `/query-details?from=${from}&to=${to}&id=${query.id}&verbose=${true}`;
144144
history.push(route);
145145
}}
146146
>
@@ -251,7 +251,7 @@ const QueryInsights = ({
251251
const isQuery = query.group_by === 'NONE';
252252
const linkContent = isQuery ? convertTime(query.timestamp) : '-';
253253
const onClickHandler = () => {
254-
const route = `/query-details?from=${from}&to=${to}&id=${query.id}`;
254+
const route = `/query-details?from=${from}&to=${to}&id=${query.id}&verbose=true`;
255255
history.push(route);
256256
};
257257
return (

public/pages/TopNQueries/TopNQueries.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ const TopNQueries = ({
171171
from: parseDateString(start),
172172
to: parseDateString(end),
173173
dataSourceId: getDataSourceFromUrl().id, // TODO: get this dynamically from the URL
174+
verbose: false,
174175
},
175176
};
176177
const fetchMetric = async (endpoint: string) => {

0 commit comments

Comments
 (0)