Skip to content

Commit eecf2c3

Browse files
Merge pull request #553 from DavidRajnoha/cypress-incidents-mocking-metric-name-change-workaround
OBSINTA-858: Cypress incidents mocking metric name change workaround
2 parents cfdeaf3 + 73b8366 commit eecf2c3

File tree

9 files changed

+114
-4
lines changed

9 files changed

+114
-4
lines changed

web/cypress.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export default defineConfig({
2222
LOGIN_USERNAME: process.env.CYPRESS_LOGIN_USERS.split(',')[0].split(':')[0],
2323
LOGIN_PASSWORD: process.env.CYPRESS_LOGIN_USERS.split(',')[0].split(':')[1],
2424
TIMEZONE: process.env.CYPRESS_TIMEZONE || 'UTC',
25+
MOCK_NEW_METRICS: process.env.CYPRESS_MOCK_NEW_METRICS || 'false',
2526
typeDelay: 200,
2627
},
2728
fixturesFolder: 'cypress/fixtures',

web/cypress/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ Set the following var to specify the cluster timezone for incident timeline calc
6767
export CYPRESS_TIMEZONE=<timezone>
6868
```
6969

70+
Set the following var to transform old metric names to new format in mocks (temporary workaround for testing against locally built instances).
71+
```bash
72+
export CYPRESS_MOCK_NEW_METRICS=false
73+
```
74+
7075
Set the following var to enable Cypress session management for faster test execution.
7176
```bash
7277
export CYPRESS_SESSION=true

web/cypress/configure-env.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ print_current_config() {
173173
print_var "CYPRESS_CUSTOM_COO_BUNDLE_IMAGE" "${CYPRESS_CUSTOM_COO_BUNDLE_IMAGE-}"
174174
print_var "CYPRESS_MCP_CONSOLE_IMAGE" "${CYPRESS_MCP_CONSOLE_IMAGE-}"
175175
print_var "CYPRESS_TIMEZONE" "${CYPRESS_TIMEZONE-}"
176+
print_var "CYPRESS_MOCK_NEW_METRICS" "${CYPRESS_MOCK_NEW_METRICS-}"
176177
print_var "CYPRESS_SESSION" "${CYPRESS_SESSION-}"
177178
print_var "CYPRESS_DEBUG" "${CYPRESS_DEBUG-}"
178179
print_var "CYPRESS_SKIP_KBV_INSTALL" "${CYPRESS_SKIP_KBV_INSTALL-}"
@@ -221,6 +222,7 @@ main() {
221222
local def_custom_coo_bundle=${CYPRESS_CUSTOM_COO_BUNDLE_IMAGE-}
222223
local def_mcp_console_image=${CYPRESS_MCP_CONSOLE_IMAGE-}
223224
local def_timezone=${CYPRESS_TIMEZONE-}
225+
local def_mock_new_metrics=${CYPRESS_MOCK_NEW_METRICS-}
224226
local def_session=${CYPRESS_SESSION-}
225227
local def_debug=${CYPRESS_DEBUG-}
226228
local def_skip_kbv=${CYPRESS_SKIP_KBV_INSTALL-}
@@ -418,6 +420,11 @@ main() {
418420
local timezone
419421
timezone=$(ask "Cluster timezone (CYPRESS_TIMEZONE)" "${def_timezone:-UTC}")
420422

423+
local mock_new_metrics_ans
424+
mock_new_metrics_ans=$(ask_yes_no "Transform old metric names to new format in mocks? (sets CYPRESS_MOCK_NEW_METRICS)" "$(bool_to_default_yn "$def_mock_new_metrics")")
425+
local mock_new_metrics="false"
426+
[[ "$mock_new_metrics_ans" == "y" ]] && mock_new_metrics="true"
427+
421428
local session_ans
422429
session_ans=$(ask_yes_no "Enable Cypress session management for faster test execution? (sets CYPRESS_SESSION)" "$(bool_to_default_yn "$def_session")")
423430
local session="false"
@@ -471,6 +478,7 @@ main() {
471478
if [[ -n "$timezone" ]]; then
472479
export_lines+=("export CYPRESS_TIMEZONE='$(printf %s "$timezone" | escape_for_single_quotes)'" )
473480
fi
481+
export_lines+=("export CYPRESS_MOCK_NEW_METRICS='$(printf %s "$mock_new_metrics" | escape_for_single_quotes)'" )
474482
export_lines+=("export CYPRESS_SESSION='$(printf %s "$session" | escape_for_single_quotes)'" )
475483
export_lines+=("export CYPRESS_DEBUG='$(printf %s "$debug" | escape_for_single_quotes)'" )
476484
if [[ -n "$skip_kbv_install" ]]; then
@@ -518,6 +526,7 @@ main() {
518526
[[ -n "${CYPRESS_CUSTOM_COO_BUNDLE_IMAGE-}$custom_coo_bundle" ]] && echo " CYPRESS_CUSTOM_COO_BUNDLE_IMAGE=${CYPRESS_CUSTOM_COO_BUNDLE_IMAGE:-$custom_coo_bundle}"
519527
[[ -n "${CYPRESS_MCP_CONSOLE_IMAGE-}$mcp_console_image" ]] && echo " CYPRESS_MCP_CONSOLE_IMAGE=${CYPRESS_MCP_CONSOLE_IMAGE:-$mcp_console_image}"
520528
[[ -n "${CYPRESS_TIMEZONE-}$timezone" ]] && echo " CYPRESS_TIMEZONE=${CYPRESS_TIMEZONE:-$timezone}"
529+
echo " CYPRESS_MOCK_NEW_METRICS=${CYPRESS_MOCK_NEW_METRICS:-$mock_new_metrics}"
521530
echo " CYPRESS_SESSION=${CYPRESS_SESSION:-$session}"
522531
echo " CYPRESS_DEBUG=${CYPRESS_DEBUG:-$debug}"
523532
echo " CYPRESS_SKIP_KBV_INSTALL=${CYPRESS_SKIP_KBV_INSTALL:-$skip_kbv_install}"

web/cypress/e2e/incidents/00.coo_incidents_e2e.cy.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ describe('BVT: Incidents - e2e', () => {
3737
});
3838

3939
it('1. Admin perspective - Incidents page - Incident with custom alert lifecycle', () => {
40+
cy.transformMetrics();
4041
cy.log('1.1 Navigate to Incidents page and clear filters');
4142
incidentsPage.goTo();
4243
incidentsPage.clearAllFilters();

web/cypress/e2e/incidents/01.incidents.cy.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ describe('BVT: Incidents - UI', () => {
4040
beforeEach(() => {
4141
cy.log('Navigate to Observe → Incidents');
4242
incidentsPage.goTo();
43+
// Temporary workaround for testing against locally built instances.
44+
cy.transformMetrics();
4345
});
4446

4547
it('1. Admin perspective - Incidents page - Toolbar and charts toggle functionality', () => {

web/cypress/fixtures/export.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,8 @@ export CYPRESS_MCP_CONSOLE_IMAGE=<Monitoring Console Plugin image>
3636
# Set the following var to specify the cluster timezone for incident timeline calculations. Defaults to UTC if not specified.
3737
export CYPRESS_TIMEZONE=<timezone>
3838

39+
# Set the following var to transform old metric names to new format in mocks (for testing against locally built instances)
40+
export CYPRESS_MOCK_NEW_METRICS=false
41+
3942
# Set the following var to enable Cypress session management for faster test execution.
4043
export CYPRESS_SESSION=true

web/cypress/support/incidents_prometheus_query_mocks/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,24 @@ const incidents: IncidentDefinition[] = [
4141
cy.mockIncidents(incidents);
4242
```
4343

44+
### Metric Transformation for Locally Built Instances
45+
46+
```typescript
47+
// Transform old metric names to new format (for testing against locally built instances)
48+
cy.transformMetrics();
49+
50+
// Then visit the page or perform actions that trigger Prometheus queries
51+
cy.visit('/monitoring/incidents');
52+
```
53+
4454
## Key Features
4555

4656
- **Schema Validation**: All YAML fixtures are validated against JSON Schema
4757
- **Query Filtering**: Mock data is filtered based on Prometheus query parameters
4858
- **Timeline Support**: Define incident start/end times and severity changes
4959
- **Timezone Configuration**: Set timezone via `CYPRESS_TIMEZONE` environment variable
5060
- **Multiple Query Types**: Supports both `cluster:health:components:map` and `ALERTS` queries
61+
- **Metric Transformation**: Transform old metric names to new format via `cy.transformMetrics()`
5162

5263
## File Structure
5364

@@ -104,6 +115,31 @@ export CYPRESS_TIMEZONE="Asia/Tokyo"
104115

105116
Default: UTC (if `CYPRESS_TIMEZONE` is not set)
106117

118+
### Metric Transformation
119+
120+
Enable transformation of old metric names to new format for testing against locally built instances:
121+
122+
```bash
123+
export CYPRESS_MOCK_NEW_METRICS=true
124+
```
125+
126+
When enabled, `cy.transformMetrics()` will intercept Prometheus queries and transform both request and response:
127+
- **Request**: `cluster:health:components:map``cluster_health_components_map`
128+
- **Response**: `cluster:health:components:map``cluster_health_components_map`
129+
130+
**Usage:**
131+
```typescript
132+
// Call before visiting pages that make Prometheus queries
133+
cy.transformMetrics();
134+
cy.visit('/monitoring/incidents');
135+
```
136+
137+
**Use Cases:**
138+
- **`CYPRESS_MOCK_NEW_METRICS=false`** (default): Test against current release/backend
139+
- **`CYPRESS_MOCK_NEW_METRICS=true`**: Test against locally built instances with new metric format
140+
141+
Default: `false` (if `CYPRESS_MOCK_NEW_METRICS` is not set)
142+
107143
## YAML Fixture Format
108144

109145
```yaml

web/cypress/support/incidents_prometheus_query_mocks/mock-generators.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { IncidentDefinition, PrometheusResult } from './types';
33
import { severityToValue, parseQueryLabels } from './utils';
44
import { nowInClusterTimezone } from './utils';
5+
import { NEW_METRIC_NAME, OLD_METRIC_NAME } from './prometheus-mocks';
56

67
/**
78
* Generates 5-minute interval timestamps between start and end time
@@ -98,6 +99,8 @@ export function createIncidentMock(incidents: IncidentDefinition[], query?: stri
9899
// Parse query to extract label selectors if provided
99100
const queryLabels = query ? parseQueryLabels(query) : {};
100101

102+
const versioned_metric = query?.includes(NEW_METRIC_NAME) ? NEW_METRIC_NAME : OLD_METRIC_NAME;
103+
101104
incidents.forEach(incident => {
102105
// Filter incidents based on query parameters
103106
if (queryLabels.group_id) {
@@ -113,7 +116,7 @@ export function createIncidentMock(incidents: IncidentDefinition[], query?: stri
113116

114117
incident.alerts.forEach(alert => {
115118
const metric: Record<string, string> = {
116-
__name__: 'cluster:health:components:map',
119+
__name__: versioned_metric,
117120
component: incident.component,
118121
layer: incident.layer,
119122
group_id: incident.id,

web/cypress/support/incidents_prometheus_query_mocks/prometheus-mocks.ts

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,40 @@ declare global {
77
interface Chainable {
88
mockIncidents(incidents: IncidentDefinition[]): Chainable<Element>;
99
mockIncidentFixture(fixturePath: string): Chainable<Element>;
10+
transformMetrics(): Chainable<Element>;
1011
}
1112
}
1213
}
1314

15+
export const NEW_METRIC_NAME = 'cluster_health_components_map';
16+
export const OLD_METRIC_NAME = 'cluster:health:components:map';
17+
const MOCK_QUERY = '/api/prometheus/api/v1/query_range*';
18+
1419
/**
1520
* Main mocking function - sets up cy.intercept for Prometheus query_range API
1621
* Intercepts the query_range API and returns the mock data for the incidents
1722
* @param incidents
1823
*/
1924
export function mockPrometheusQueryRange(incidents: IncidentDefinition[]): void {
20-
cy.intercept('GET', '/api/prometheus/api/v1/query_range*', (req) => {
25+
cy.intercept('GET', MOCK_QUERY, (req) => {
2126
const url = new URL(req.url, window.location.origin);
2227
const query = url.searchParams.get('query') || '';
2328

2429
console.log(`INTERCEPTED: ${req.method} ${req.url}`);
2530
console.log(`Query: ${query}`);
2631

2732
let results: any[];
33+
34+
const versioned_metric = query.includes(NEW_METRIC_NAME)
35+
? NEW_METRIC_NAME: OLD_METRIC_NAME;
2836

29-
if (!(query.includes('cluster:health:components:map') || query.includes('ALERTS{'))) {
37+
if (!(query.includes(versioned_metric) || query.includes('ALERTS{'))) {
3038
console.log(`Passing through non-mocked query`);
3139
req.continue();
3240
return;
3341
}
3442

35-
results = query.includes('cluster:health:components:map') ? createIncidentMock(incidents, query) : createAlertDetailsMock(incidents, query);
43+
results = query.includes(versioned_metric) ? createIncidentMock(incidents, query) : createAlertDetailsMock(incidents, query);
3644
const response: PrometheusResponse = {
3745
status: 'success',
3846
data: {
@@ -85,4 +93,46 @@ Cypress.Commands.add('mockIncidentFixture', (fixturePath: string) => {
8593

8694
// The mocking is not applied until the page is reloaded and the components fetch the new data
8795
cy.reload();
96+
});
97+
98+
Cypress.Commands.add('transformMetrics', () => {
99+
cy.log('=== SETTING UP METRIC TRANSFORMATION ===');
100+
const mockNewMetrics = Cypress.env('MOCK_NEW_METRICS') === true;
101+
102+
if (!mockNewMetrics) {
103+
cy.log('CYPRESS_MOCK_NEW_METRICS is disabled, skipping transformation');
104+
return;
105+
}
106+
107+
cy.log('Transforming old metric queries to new format');
108+
109+
cy.intercept('GET', MOCK_QUERY, (req) => {
110+
const url = new URL(req.url, window.location.origin);
111+
const query = url.searchParams.get('query') || '';
112+
const hasNewMetric = query.includes(NEW_METRIC_NAME);
113+
114+
if (hasNewMetric) {
115+
const transformedQuery = query.replace(new RegExp(NEW_METRIC_NAME, 'g'), OLD_METRIC_NAME);
116+
console.log(`Transforming metric query: ${query} -> ${transformedQuery}`);
117+
118+
// Update the URL with the transformed query
119+
url.searchParams.set('query', transformedQuery);
120+
req.url = url.toString();
121+
122+
// Also transform the response to use new metric names
123+
req.continue((res) => {
124+
if (res.body?.data?.result) {
125+
res.body.data.result.forEach((result: any) => {
126+
if (result?.metric?.__name__ === OLD_METRIC_NAME) {
127+
console.log(`Transforming response metric name: ${OLD_METRIC_NAME} -> ${NEW_METRIC_NAME}`);
128+
result.metric.__name__ = NEW_METRIC_NAME;
129+
}
130+
});
131+
}
132+
res.send();
133+
});
134+
} else {
135+
req.continue();
136+
}
137+
});
88138
});

0 commit comments

Comments
 (0)