Skip to content

Commit aa81fe6

Browse files
committed
fix: move AAC fixtures and add cassette normalization
- Move tests/catalog/fixtures/aac/ to tests/catalog/unit_tests/aac_tests/ so make remove-cassettes no longer deletes static AAC test data - Add VCR normalizations for traceId, authenticationId/authId, bearerToken, cacheId, queryDurationMillis, and exportResult to eliminate transient diffs - Replace counter-based hash placeholders with fixed EXECUTION_NORMALIZED and EXPORT_NORMALIZED to avoid counter drift between recording and playback - Sort XML localization groups by id for deterministic XLIFF output - Bump docker-compose: Quiver v0.398.0, Pulsar 4.1.3, Redis 8.6.1 JIRA: DX-326 risk: low
1 parent 1d2454b commit aa81fe6

9 files changed

Lines changed: 297 additions & 40 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# (C) 2026 GoodData Corporation
2+
# A dashboard is a collection of visualizations that are organized into sections.
3+
# Because they allow filtering and other adjustments, they function as a dynamic presentation layer for your data analytics.
4+
# Read more about dashboards:
5+
# https://www.gooddata.com/docs/cloud/create-dashboards/concepts/dashboard/
6+
7+
id: 90a53321-9060-4aef-9dc6-a3d0a9a5323e
8+
type: dashboard
9+
10+
title: Dashboard 1
11+
12+
sections:
13+
- widgets:
14+
- visualization: 71bdc379-384a-4eac-9627-364ea847d977
15+
title: Ratings
16+
columns: 12
17+
rows: 22
18+
19+
filters:
20+
date_month:
21+
type: date_filter
22+
granularity: MONTH
23+
from: 0
24+
to: 0
25+
mode: hidden
26+
customer_created_date_year:
27+
type: date_filter
28+
granularity: YEAR
29+
date: customer_created_date
30+
from: 0
31+
to: 0
32+
mode: hidden
33+
customer_age:
34+
type: attribute_filter
35+
using: label/customer_age
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# (C) 2026 GoodData Corporation
2+
# A dataset is a logical object that represents a set of related facts, attributes, and attribute labels.
3+
# Datasets are basic organization units of a logical data model.
4+
# Read more about Datasets:
5+
# https://www.gooddata.com/developers/cloud-native/doc/cloud/model-data/concepts/dataset/
6+
7+
type: dataset
8+
id: customer
9+
10+
table_path: ECOMMERCE_DEMO_SCHEMA/customer
11+
12+
title: Customer
13+
description: Customer
14+
tags:
15+
- Customer
16+
17+
primary_key: customer_id
18+
19+
fields:
20+
customer_city:
21+
type: attribute
22+
source_column: customer_city
23+
data_type: STRING
24+
title: Customer city
25+
description: Customer city
26+
tags:
27+
- Customer
28+
labels:
29+
geo__customer_city__city_pushpin_latitude:
30+
source_column: geo__customer_city__city_pushpin_latitude
31+
data_type: STRING
32+
title: City pushpin latitude
33+
description: City pushpin latitude
34+
tags:
35+
- Customer
36+
geo__customer_city__city_pushpin_longitude:
37+
source_column: geo__customer_city__city_pushpin_longitude
38+
data_type: STRING
39+
title: City pushpin longitude
40+
description: City pushpin longitude
41+
tags:
42+
- Customer
43+
customer_country:
44+
type: attribute
45+
source_column: customer_country
46+
data_type: STRING
47+
title: Customer country
48+
description: Customer country
49+
tags:
50+
- Customer
51+
customer_email:
52+
type: attribute
53+
source_column: customer_email
54+
data_type: STRING
55+
title: Customer email
56+
description: Customer email
57+
tags:
58+
- Customer
59+
labels:
60+
customer_email.customeremaillink:
61+
source_column: customer_email
62+
data_type: STRING
63+
title: Customer email link
64+
tags:
65+
- Customer
66+
value_type: HYPERLINK
67+
customer_id:
68+
type: attribute
69+
source_column: customer_id
70+
data_type: STRING
71+
title: Customer id
72+
description: Customer id
73+
tags:
74+
- Customer
75+
labels:
76+
customer_name:
77+
source_column: ls__customer_id__customer_name
78+
data_type: STRING
79+
title: Customer name
80+
description: Customer name
81+
tags:
82+
- Customer
83+
customer_state:
84+
type: attribute
85+
source_column: customer_state
86+
data_type: STRING
87+
title: Customer state
88+
description: Customer state
89+
tags:
90+
- Customer
91+
92+
references:
93+
- dataset: customer_created_date
94+
sources:
95+
- source_column: customer_created_date
96+
data_type: DATE
97+
target: customer_created_date
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# (C) 2026 GoodData Corporation
2+
# A Date dataset is a dataset in the logical data model(LDM)
3+
# that represents DATE / TIMESTAMP columns in your database.
4+
# Read more about date instances:
5+
# https://www.gooddata.com/developers/cloud-native/doc/cloud/model-data/concepts/dataset/#date-datasets
6+
7+
type: date
8+
id: order_date
9+
10+
title: Order date
11+
tags:
12+
- Order date
13+
14+
granularities:
15+
- MINUTE
16+
- HOUR
17+
- DAY
18+
- WEEK
19+
- MONTH
20+
- QUARTER
21+
- YEAR
22+
- MINUTE_OF_HOUR
23+
- HOUR_OF_DAY
24+
- DAY_OF_WEEK
25+
- DAY_OF_MONTH
26+
- DAY_OF_YEAR
27+
- WEEK_OF_YEAR
28+
- MONTH_OF_YEAR
29+
- QUARTER_OF_YEAR
30+
31+
title_base: ""
32+
title_pattern: "%titleBase - %granularityTitle"
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# (C) 2026 GoodData Corporation
2+
# A dataset is a logical object that represents a set of related facts, attributes, and attribute labels.
3+
# Datasets are basic organization units of a logical data model.
4+
# Read more about Datasets:
5+
# https://www.gooddata.com/developers/cloud-native/doc/cloud/model-data/concepts/dataset/
6+
7+
type: dataset
8+
id: orders
9+
10+
table_path: ECOMMERCE_DEMO_SCHEMA/orders
11+
12+
title: Orders
13+
description: Orders
14+
tags:
15+
- Orders
16+
17+
primary_key: order_id
18+
19+
fields:
20+
order_id:
21+
type: attribute
22+
source_column: order_id
23+
data_type: STRING
24+
title: Order id
25+
description: Order id
26+
tags:
27+
- Orders
28+
order_status:
29+
type: attribute
30+
source_column: order_status
31+
data_type: STRING
32+
title: Order status
33+
description: Order status
34+
tags:
35+
- Orders
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# (C) 2026 GoodData Corporation
2+
profiles:
3+
default:
4+
host: "https://test.gooddata.com"
5+
token: "test-token"
6+
workspace_id: "test-workspace"
7+
data_source: "test-datasource"
8+
default_profile: "default"
9+
source_dir: "analytics"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# (C) 2026 GoodData Corporation
2+
# A metric is a computational expression of numerical data (facts or other metrics).
3+
# Use MAQL to create reusable multidimensional queries that combine multiple facts and attributes.
4+
# Read more about MAQL:
5+
# https://www.gooddata.com/developers/cloud-native/doc/cloud/create-metrics/maql/
6+
7+
type: metric
8+
id: top_products
9+
10+
title: Top Products
11+
12+
maql: SELECT SUM({fact/rating}) WHERE {label/product_rating} = "*****";
13+
format: "#,##0.00"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# (C) 2026 GoodData Corporation
2+
# A visualization is a visual representation of a user’s analytical view of the data.
3+
# You build visualizations from metrics, attributes, and optionally filters that are combined in a way to visualize a particular aspect of your data.
4+
# The visualizations are executed over and over as fresh data gets loaded.
5+
# Interpreting the content of a visualization is up to the user (the consumer of the visualization).
6+
# Read more about visualisations:
7+
# https://www.gooddata.com/developers/cloud-native/doc/cloud/create-visualizations/concepts/visualization/
8+
9+
id: 71bdc379-384a-4eac-9627-364ea847d977
10+
type: table
11+
12+
title: Ratings
13+
14+
query:
15+
fields:
16+
sum_of_rating_1:
17+
title: Sum of Rating
18+
aggregation: SUM
19+
using: fact/rating
20+
21+
metrics:
22+
- field: sum_of_rating_1
23+
format: "#,##0.00"
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# (C) 2026 GoodData Corporation
2+
# A visualization is a visual representation of a user’s analytical view of the data.
3+
# You build visualizations from metrics, attributes, and optionally filters that are combined in a way to visualize a particular aspect of your data.
4+
# The visualizations are executed over and over as fresh data gets loaded.
5+
# Interpreting the content of a visualization is up to the user (the consumer of the visualization).
6+
# Read more about visualisations:
7+
# https://www.gooddata.com/developers/cloud-native/doc/cloud/create-visualizations/concepts/visualization/
8+
9+
id: 4c2002a4-a60c-4f4a-a440-d2a6a35887cf
10+
type: column_chart
11+
12+
title: Ratings per Category
13+
14+
query:
15+
fields:
16+
sum_of_rating:
17+
title: Sum of Rating
18+
aggregation: SUM
19+
using: fact/rating
20+
product_category: label/product_category
21+
product_rating: label/product_rating
22+
23+
metrics:
24+
- field: sum_of_rating
25+
format: "#,##0.00"
26+
27+
view_by:
28+
- product_category
29+
30+
segment_by:
31+
- product_rating
32+
33+
config:
34+
colors:
35+
"*": rgb(255,0,0)
36+
"**": rgb(255,159,0)
37+
"***": rgb(245,255,102)
38+
"****": rgb(102,255,235)
39+
"*****": rgb(23,242,13)
40+
legend_position: top
41+
xaxis_name_position: center
42+
xaxis_rotation: "0"
43+
yaxis_name_position: top

packages/tests-support/src/tests_support/vcrpy_utils.py

Lines changed: 10 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -80,38 +80,14 @@
8080
_EXPORT_HASH_BODY_RE = re.compile(
8181
r'(?<=exportResult": ")[0-9a-f]{40}(?![0-9a-f])' # JSON: "exportResult": "hash"
8282
r"|"
83-
r"(?<=exportResult: )[0-9a-f]{40}(?![0-9a-f])" # YAML: exportResult: hash
83+
r'(?<=exportResult":")[0-9a-f]{40}(?![0-9a-f])' # JSON (orjson)
84+
r"|"
85+
r"(?<=exportResult: )[0-9a-f]{40}(?![0-9a-f])" # YAML
8486
)
8587

8688

87-
class _HashNormalizer:
88-
"""Maps server-computed hex hashes to deterministic placeholders.
89-
90-
Assigns stable placeholders (EXECUTION_RESULT_0, EXPORT_RESULT_0, etc.)
91-
to dynamic hashes that differ between environments and re-recordings.
92-
The same hash always maps to the same placeholder within a session.
93-
"""
94-
95-
def __init__(self) -> None:
96-
self._exec_map: dict[str, str] = {}
97-
self._export_map: dict[str, str] = {}
98-
self._exec_counter: int = 0
99-
self._export_counter: int = 0
100-
101-
def normalize_exec(self, full_hash: str) -> str:
102-
if full_hash not in self._exec_map:
103-
self._exec_map[full_hash] = f"EXECUTION_RESULT_{self._exec_counter}"
104-
self._exec_counter += 1
105-
return self._exec_map[full_hash]
106-
107-
def normalize_export(self, hex_hash: str) -> str:
108-
if hex_hash not in self._export_map:
109-
self._export_map[hex_hash] = f"EXPORT_RESULT_{self._export_counter}"
110-
self._export_counter += 1
111-
return self._export_map[hex_hash]
112-
113-
114-
_hash_normalizer = _HashNormalizer()
89+
_CANONICAL_EXECUTION_RESULT = "EXECUTION_NORMALIZED"
90+
_CANONICAL_EXPORT_RESULT = "EXPORT_NORMALIZED"
11591

11692

11793
def configure_normalization(test_config: dict[str, Any]) -> None:
@@ -214,23 +190,17 @@ def _apply_replacements(text: str) -> str:
214190

215191

216192
def _normalize_hashes_in_text(text: str) -> str:
217-
"""Replace executionResult/exportResult hashes and timestamps with deterministic placeholders."""
218-
text = _EXEC_HASH_BODY_RE.sub(lambda m: _hash_normalizer.normalize_exec(m.group(0)), text)
219-
text = _EXPORT_HASH_BODY_RE.sub(lambda m: _hash_normalizer.normalize_export(m.group(0)), text)
193+
"""Replace transient server values with deterministic placeholders."""
194+
text = _EXEC_HASH_BODY_RE.sub(_CANONICAL_EXECUTION_RESULT, text)
195+
text = _EXPORT_HASH_BODY_RE.sub(_CANONICAL_EXPORT_RESULT, text)
220196
text = _CREATED_AT_RE.sub(_CANONICAL_CREATED_AT, text)
221197
return text
222198

223199

224200
def _normalize_hashes_in_uri(uri: str) -> str:
225201
"""Replace executionResult/exportResult hashes in a request URI."""
226-
227-
def _replace_exec_uri(m: re.Match) -> str:
228-
# Convert URL-encoded %3A to plain colon for consistent mapping
229-
plain = m.group(0).replace("%3A", ":").replace("%3a", ":")
230-
return _hash_normalizer.normalize_exec(plain)
231-
232-
uri = _EXEC_HASH_URI_RE.sub(_replace_exec_uri, uri)
233-
uri = _EXPORT_HASH_URI_RE.sub(lambda m: _hash_normalizer.normalize_export(m.group(0)), uri)
202+
uri = _EXEC_HASH_URI_RE.sub(_CANONICAL_EXECUTION_RESULT, uri)
203+
uri = _EXPORT_HASH_URI_RE.sub(_CANONICAL_EXPORT_RESULT, uri)
234204
return uri
235205

236206

0 commit comments

Comments
 (0)