Skip to content

Commit 401565c

Browse files
committed
Onboard query insights dashboards onto functional test repo
Signed-off-by: Chenyang Ji <cyji@amazon.com>
1 parent af7d4e6 commit 401565c

File tree

12 files changed

+737
-0
lines changed

12 files changed

+737
-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,116 @@
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+
/**
59+
* Validate sorting by the "Timestamp" column works correctly
60+
*/
61+
it('should sort the table by the Timestamp column', () => {
62+
// waiting for the query insights queue to drain
63+
cy.wait(10000);
64+
cy.navigateToOverview();
65+
// Click the Timestamp column header to sort
66+
cy.get('.euiTableHeaderCell').contains('Timestamp').click();
67+
cy.get('.euiTableRow')
68+
.first()
69+
.invoke('text')
70+
.then((firstRowAfterSort) => {
71+
const firstTimestamp = firstRowAfterSort.trim();
72+
cy.get('.euiTableHeaderCell').contains('Timestamp').click();
73+
cy.get('.euiTableRow')
74+
.first()
75+
.invoke('text')
76+
.then((firstRowAfterSecondSort) => {
77+
expect(firstRowAfterSecondSort.trim()).to.not.equal(firstTimestamp);
78+
});
79+
});
80+
});
81+
82+
it('should switch between tabs', () => {
83+
// Click Configuration tab
84+
cy.getElementByText('.euiTab', 'Configuration').click({ force: true });
85+
cy.contains('Query insights - Configuration');
86+
cy.url().should('include', '/configuration');
87+
88+
// Click back to Query Insights tab
89+
cy.getElementByText('.euiTab', 'Top N queries').click({ force: true });
90+
cy.url().should('include', '/queryInsights');
91+
});
92+
93+
it('should filter queries', () => {
94+
cy.get('.euiFieldSearch').should('be.visible');
95+
cy.get('.euiFieldSearch').type('sample_index');
96+
// Add assertions for filtered results
97+
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
98+
});
99+
100+
it('should clear the search input and reset results', () => {
101+
cy.get('.euiFieldSearch').type('random_string');
102+
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
103+
cy.get('.euiFieldSearch').clear();
104+
cy.get('.euiTableRow').should('have.length.greaterThan', 0); // Validate reset
105+
});
106+
107+
it('should display a message when no top queries are found', () => {
108+
clearAll(); // disable top n queries
109+
// waiting for the query insights queue to drain
110+
cy.wait(10000);
111+
cy.reload();
112+
cy.contains('No items found');
113+
});
114+
115+
after(() => clearAll());
116+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
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.get('.euiTableRow').first().find('button').first().trigger('mouseover');
32+
cy.wait(1000);
33+
cy.get('.euiTableRow').first().find('button').first().click(); // Navigate to details
34+
cy.wait(1000);
35+
});
36+
37+
it('should display correct details on the query details page', () => {
38+
// cy.get('.euiBasicTable a').first().click(); // Navigate to details
39+
cy.url().should('include', '/query-details');
40+
// Validate the page title
41+
cy.get('h1').contains('Query details').should('be.visible');
42+
// Validate the summary section
43+
cy.get('[data-test-subj="query-details-summary-section"]').should(
44+
'be.visible'
45+
);
46+
// Validate the presence of latency chart
47+
cy.get('[data-test-subj="query-details-latency-chart"]').should(
48+
'be.visible'
49+
);
50+
// Validate the presence of query source details section
51+
cy.get('[data-test-subj="query-details-source-section"]').should(
52+
'be.visible'
53+
);
54+
});
55+
56+
/**
57+
* Validate summary panel has valid labels
58+
*/
59+
it('the summary panel should display correctly', () => {
60+
// Validate all field labels exist
61+
const fieldLabels = [
62+
'Timestamp',
63+
'Latency',
64+
'CPU Time',
65+
'Memory Usage',
66+
'Indices',
67+
'Search Type',
68+
'Coordinator Node ID',
69+
'Total Shards',
70+
];
71+
fieldLabels.forEach((label) => {
72+
cy.get('.euiPanel').contains('h4', label).should('be.visible');
73+
});
74+
});
75+
76+
/**
77+
* Validate each field in the summary panel has valid content
78+
*/
79+
it('should display correct values for all fields in the summary panel', () => {
80+
cy.get('[data-test-subj="query-details-summary-section"]').within(() => {
81+
// Validate Timestamp
82+
cy.contains('h4', 'Timestamp')
83+
.parent()
84+
.next()
85+
.invoke('text')
86+
.should('match', /\w{3} \d{2}, \d{4} @ \d{1,2}:\d{2}:\d{2} [AP]M/);
87+
// Validate Latency
88+
cy.contains('h4', 'Latency')
89+
.parent()
90+
.next()
91+
.invoke('text')
92+
.should('match', /^\d+(\.\d{1,2})? ms$/);
93+
// Validate CPU Time
94+
cy.contains('h4', 'CPU Time')
95+
.parent()
96+
.next()
97+
.invoke('text')
98+
.should('match', /^\d+(\.\d+)? ms$/);
99+
// Validate Memory Usage
100+
cy.contains('h4', 'Memory Usage')
101+
.parent()
102+
.next()
103+
.invoke('text')
104+
.should('match', /^\d+(\.\d+)? B$/);
105+
// Validate Indices
106+
cy.contains('h4', 'Indices')
107+
.parent()
108+
.next()
109+
.invoke('text')
110+
.should('not.be.empty');
111+
// Validate Search Type
112+
cy.contains('h4', 'Search Type')
113+
.parent()
114+
.next()
115+
.invoke('text')
116+
.should('equal', 'query then fetch');
117+
// Validate Coordinator Node ID
118+
cy.contains('h4', 'Coordinator Node ID')
119+
.parent()
120+
.next()
121+
.invoke('text')
122+
.should('not.be.empty');
123+
// Validate Total Shards
124+
cy.contains('h4', 'Total Shards')
125+
.parent()
126+
.next()
127+
.invoke('text')
128+
.then((text) => {
129+
const shardCount = parseInt(text.trim(), 10);
130+
expect(shardCount).to.be.a('number').and.to.be.greaterThan(0);
131+
});
132+
});
133+
});
134+
135+
/**
136+
* Validate the latency chart interaction
137+
*/
138+
it('should render the latency chart and allow interaction', () => {
139+
// Ensure the chart is visible
140+
cy.get('#latency').should('be.visible');
141+
cy.get('.plot-container').should('be.visible');
142+
// Simulate hover over the chart for a data point
143+
cy.get('#latency').trigger('mousemove', { clientX: 100, clientY: 100 });
144+
});
145+
146+
after(() => clearAll());
147+
});

0 commit comments

Comments
 (0)