Skip to content

Commit db2594d

Browse files
Onboard query insights dashboards onto functional test repo (#1689) (#1691) (#1692)
Signed-off-by: Chenyang Ji <cyji@amazon.com> (cherry picked from commit 028e8d8) Co-authored-by: Chenyang Ji <chenyang.yale@gmail.com>
1 parent 221590d commit db2594d

File tree

12 files changed

+711
-0
lines changed

12 files changed

+711
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Query Insights Dashboards Release tests workflow in Bundled OpenSearch Dashboards
2+
on:
3+
pull_request:
4+
branches: [ '**' ]
5+
jobs:
6+
changes:
7+
runs-on: ubuntu-latest
8+
outputs:
9+
tests: ${{ steps.filter.outputs.tests }}
10+
steps:
11+
- uses: dorny/paths-filter@v2
12+
id: filter
13+
with:
14+
filters: |
15+
tests:
16+
- 'cypress/**/query-insights-dashboards/**'
17+
18+
tests:
19+
needs: changes
20+
if: ${{ needs.changes.outputs.tests == 'true' }}
21+
uses: ./.github/workflows/release-e2e-workflow-template.yml
22+
with:
23+
test-name: Query Insights Dashboards
24+
test-command: env CYPRESS_NO_COMMAND_LOG=1 yarn cypress:run-with-security --browser chromium --spec 'cypress/integration/plugins/query-insights-dashboards/*'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"@timestamp": "2099-11-15T13:12:00",
3+
"message": "this is document 0",
4+
"user": {
5+
"id": "user1",
6+
"name": "John Doe",
7+
"email": "john.doe@example.com",
8+
"roles": ["admin", "editor"]
9+
},
10+
"request": {
11+
"method": "GET",
12+
"url": "/api/v1/resource",
13+
"status": 200,
14+
"response_time_ms": 123,
15+
"headers": {
16+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
17+
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5..."
18+
}
19+
},
20+
"location": {
21+
"ip": "192.168.1.1",
22+
"city": "Seattle",
23+
"region": "Washington",
24+
"country": "US"
25+
},
26+
"application": {
27+
"name": "OpenSearch Dashboard",
28+
"version": "2.8.0",
29+
"environment": "production"
30+
},
31+
"event": {
32+
"id": "event123",
33+
"type": "user_action",
34+
"outcome": "success",
35+
"reason": null
36+
},
37+
"tags": ["login", "dashboard", "analytics"],
38+
"metrics": {
39+
"cpu_usage": 2.4,
40+
"memory_usage": 512,
41+
"disk_space_remaining": 1048576
42+
}
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import sampleDocument from '../../../fixtures/plugins/query-insights-dashboards/sample_document.json';
7+
import { QUERY_INSIGHTS_METRICS } from '../../../utils/constants';
8+
9+
// Name of the test index used in tests
10+
const indexName = 'sample_index';
11+
12+
/**
13+
Helper function to clean up the environment:
14+
- Deletes the test index.
15+
- Disables the top queries features.
16+
*/
17+
const clearAll = () => {
18+
cy.deleteIndexByName(indexName);
19+
cy.disableTopQueries(QUERY_INSIGHTS_METRICS.LATENCY);
20+
cy.disableTopQueries(QUERY_INSIGHTS_METRICS.CPU);
21+
cy.disableTopQueries(QUERY_INSIGHTS_METRICS.MEMORY);
22+
};
23+
24+
describe('Query Insights Dashboard', () => {
25+
// Setup before each test
26+
beforeEach(() => {
27+
clearAll();
28+
cy.createIndexByName(indexName, sampleDocument);
29+
cy.enableTopQueries(QUERY_INSIGHTS_METRICS.LATENCY);
30+
cy.enableTopQueries(QUERY_INSIGHTS_METRICS.CPU);
31+
cy.enableTopQueries(QUERY_INSIGHTS_METRICS.MEMORY);
32+
cy.searchOnIndex(indexName);
33+
// wait for 1s to avoid same timestamp
34+
cy.wait(1000);
35+
cy.searchOnIndex(indexName);
36+
cy.wait(1000);
37+
cy.searchOnIndex(indexName);
38+
// waiting for the query insights queue to drain
39+
cy.wait(10000);
40+
cy.navigateToOverview();
41+
});
42+
43+
/**
44+
* Validate the main overview page loads correctly
45+
*/
46+
it('should display the main overview page', () => {
47+
cy.get('.euiBasicTable').should('be.visible');
48+
cy.contains('Query insights - Top N queries');
49+
cy.url().should('include', '/queryInsights');
50+
51+
// should display the query table on the overview page
52+
cy.get('.euiBasicTable').should('be.visible');
53+
cy.get('.euiTableHeaderCell').should('have.length.greaterThan', 0);
54+
// should have top n queries displayed on the table
55+
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
56+
});
57+
58+
it('should switch between tabs', () => {
59+
// Click Configuration tab
60+
cy.getElementByText('.euiTab', 'Configuration').click({ force: true });
61+
cy.contains('Query insights - Configuration');
62+
cy.url().should('include', '/configuration');
63+
64+
// Click back to Query Insights tab
65+
cy.getElementByText('.euiTab', 'Top N queries').click({ force: true });
66+
cy.url().should('include', '/queryInsights');
67+
});
68+
69+
it('should filter queries', () => {
70+
cy.get('.euiFieldSearch').should('be.visible');
71+
cy.get('.euiFieldSearch').type('sample_index');
72+
// Add assertions for filtered results
73+
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
74+
});
75+
76+
it('should clear the search input and reset results', () => {
77+
cy.get('.euiFieldSearch').type('random_string');
78+
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
79+
cy.get('.euiFieldSearch').clear();
80+
cy.get('.euiTableRow').should('have.length.greaterThan', 0); // Validate reset
81+
});
82+
83+
it('should display a message when no top queries are found', () => {
84+
clearAll(); // disable top n queries
85+
// waiting for the query insights queue to drain
86+
cy.wait(10000);
87+
cy.reload();
88+
cy.contains('No items found');
89+
});
90+
91+
after(() => clearAll());
92+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import sampleDocument from '../../../fixtures/plugins/query-insights-dashboards/sample_document.json';
7+
import { QUERY_INSIGHTS_METRICS } from '../../../utils/constants';
8+
9+
const indexName = 'sample_index';
10+
11+
const clearAll = () => {
12+
cy.deleteIndexByName(indexName);
13+
cy.disableTopQueries(QUERY_INSIGHTS_METRICS.LATENCY);
14+
cy.disableTopQueries(QUERY_INSIGHTS_METRICS.CPU);
15+
cy.disableTopQueries(QUERY_INSIGHTS_METRICS.MEMORY);
16+
};
17+
18+
describe('Top Queries Details Page', () => {
19+
beforeEach(() => {
20+
clearAll();
21+
cy.createIndexByName(indexName, sampleDocument);
22+
cy.enableTopQueries(QUERY_INSIGHTS_METRICS.LATENCY);
23+
cy.enableTopQueries(QUERY_INSIGHTS_METRICS.CPU);
24+
cy.enableTopQueries(QUERY_INSIGHTS_METRICS.MEMORY);
25+
cy.searchOnIndex(indexName);
26+
cy.searchOnIndex(indexName);
27+
cy.searchOnIndex(indexName);
28+
// waiting for the query insights queue to drain
29+
cy.wait(10000);
30+
cy.navigateToOverview();
31+
cy.wait(10000);
32+
cy.get('.euiTableRow').first().find('button').first().trigger('mouseover');
33+
cy.wait(1000);
34+
cy.get('.euiTableRow').first().find('button').first().click(); // Navigate to details
35+
cy.wait(1000);
36+
});
37+
38+
it('should display correct details on the query details page', () => {
39+
// cy.get('.euiBasicTable a').first().click(); // Navigate to details
40+
cy.url().should('include', '/query-details');
41+
// Validate the page title
42+
cy.get('h1').contains('Query details').should('be.visible');
43+
// Validate the summary section
44+
cy.get('[data-test-subj="query-details-summary-section"]').should(
45+
'be.visible'
46+
);
47+
// Validate the presence of latency chart
48+
cy.get('[data-test-subj="query-details-latency-chart"]').should(
49+
'be.visible'
50+
);
51+
// Validate the presence of query source details section
52+
cy.get('[data-test-subj="query-details-source-section"]').should(
53+
'be.visible'
54+
);
55+
});
56+
57+
/**
58+
* Validate summary panel has valid labels
59+
*/
60+
it('the summary panel should display correctly', () => {
61+
// Validate all field labels exist
62+
const fieldLabels = [
63+
'Timestamp',
64+
'Latency',
65+
'CPU Time',
66+
'Memory Usage',
67+
'Indices',
68+
'Search Type',
69+
'Coordinator Node ID',
70+
'Total Shards',
71+
];
72+
fieldLabels.forEach((label) => {
73+
cy.get('.euiPanel').contains('h4', label).should('be.visible');
74+
});
75+
});
76+
77+
/**
78+
* Validate each field in the summary panel has valid content
79+
*/
80+
it('should display correct values for all fields in the summary panel', () => {
81+
cy.get('[data-test-subj="query-details-summary-section"]').within(() => {
82+
// Validate Timestamp
83+
cy.contains('h4', 'Timestamp')
84+
.parent()
85+
.next()
86+
.invoke('text')
87+
.should('match', /\w{3} \d{2}, \d{4} @ \d{1,2}:\d{2}:\d{2} [AP]M/);
88+
// Validate Latency
89+
cy.contains('h4', 'Latency')
90+
.parent()
91+
.next()
92+
.invoke('text')
93+
.should('match', /^\d+(\.\d{1,2})? ms$/);
94+
// Validate CPU Time
95+
cy.contains('h4', 'CPU Time')
96+
.parent()
97+
.next()
98+
.invoke('text')
99+
.should('match', /^\d+(\.\d+)? ms$/);
100+
// Validate Memory Usage
101+
cy.contains('h4', 'Memory Usage')
102+
.parent()
103+
.next()
104+
.invoke('text')
105+
.should('match', /^\d+(\.\d+)? B$/);
106+
// Validate Indices
107+
cy.contains('h4', 'Indices')
108+
.parent()
109+
.next()
110+
.invoke('text')
111+
.should('not.be.empty');
112+
// Validate Search Type
113+
cy.contains('h4', 'Search Type')
114+
.parent()
115+
.next()
116+
.invoke('text')
117+
.should('equal', 'query then fetch');
118+
// Validate Coordinator Node ID
119+
cy.contains('h4', 'Coordinator Node ID')
120+
.parent()
121+
.next()
122+
.invoke('text')
123+
.should('not.be.empty');
124+
// Validate Total Shards
125+
cy.contains('h4', 'Total Shards')
126+
.parent()
127+
.next()
128+
.invoke('text')
129+
.then((text) => {
130+
const shardCount = parseInt(text.trim(), 10);
131+
expect(shardCount).to.be.a('number').and.to.be.greaterThan(0);
132+
});
133+
});
134+
});
135+
136+
/**
137+
* Validate the latency chart interaction
138+
*/
139+
it('should render the latency chart and allow interaction', () => {
140+
// Ensure the chart is visible
141+
cy.get('#latency').should('be.visible');
142+
cy.get('.plot-container').should('be.visible');
143+
// Simulate hover over the chart for a data point
144+
cy.get('#latency').trigger('mousemove', { clientX: 100, clientY: 100 });
145+
});
146+
147+
after(() => clearAll());
148+
});

0 commit comments

Comments
 (0)