diff --git a/config/contracts/metric.avg_order_value.v1.yaml b/config/contracts/metric.avg_order_value.v1.yaml index 9c24fb27..babc9807 100644 --- a/config/contracts/metric.avg_order_value.v1.yaml +++ b/config/contracts/metric.avg_order_value.v1.yaml @@ -6,7 +6,7 @@ fields: - name: value type: float required: true - unit: USD + unit: RUB - name: unit type: string required: true diff --git a/config/contracts/metric.revenue.v1.yaml b/config/contracts/metric.revenue.v1.yaml index f6a95129..6d24f74c 100644 --- a/config/contracts/metric.revenue.v1.yaml +++ b/config/contracts/metric.revenue.v1.yaml @@ -6,7 +6,7 @@ fields: - name: value type: float required: true - unit: USD + unit: RUB - name: unit type: string required: true diff --git a/contracts/entities/order.yaml b/contracts/entities/order.yaml index 3a140490..6a7c7e22 100644 --- a/contracts/entities/order.yaml +++ b/contracts/entities/order.yaml @@ -7,7 +7,7 @@ fields: user_id: Customer identifier status: "Current status: pending, confirmed, shipped, delivered, cancelled" total_amount: Order total in the order currency - currency: ISO 4217 alpha-3 currency code (USD, EUR, GBP) + currency: ISO 4217 alpha-3 currency code (RUB primary; AED/KZT on branch-currency reads) created_at: Order creation timestamp relationships: user: user_id diff --git a/docs/api-reference.md b/docs/api-reference.md index b66ca691..457ccfb7 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -233,7 +233,7 @@ console.log(Object.keys(catalog.entities)); **Response 200** ```json -{"entities":{"order":{"primary_key":"order_id"}},"metrics":{"revenue":{"unit":"USD"}}} +{"entities":{"order":{"primary_key":"order_id"}},"metrics":{"revenue":{"unit":"RUB"}}} ``` **Errors:** `401`, `429`. @@ -313,7 +313,7 @@ console.log(metric.value, metric.unit); **Response 200** ```json -{"metric_name":"revenue","value":984.91,"unit":"USD","window":"1h","components":null} +{"metric_name":"revenue","value":12750.00,"unit":"RUB","window":"1h","components":null} ``` **Errors:** `401`, `404`, `422` for invalid historical anchor, `503` if metric computation cannot run. diff --git a/scripts/generate_contracts.py b/scripts/generate_contracts.py index 97139d77..cc6f5a67 100644 --- a/scripts/generate_contracts.py +++ b/scripts/generate_contracts.py @@ -148,7 +148,7 @@ class ContractSpec: ), field_overrides={ "value": { - "unit": "USD", + "unit": "RUB", }, }, source_events=ORDER_SOURCE_EVENTS, @@ -192,7 +192,7 @@ class ContractSpec: ), field_overrides={ "value": { - "unit": "USD", + "unit": "RUB", }, }, source_events=ORDER_SOURCE_EVENTS, diff --git a/src/serving/backends/clickhouse_backend.py b/src/serving/backends/clickhouse_backend.py index 41d4b217..99befffc 100644 --- a/src/serving/backends/clickhouse_backend.py +++ b/src/serving/backends/clickhouse_backend.py @@ -451,16 +451,16 @@ def ts(delta: timedelta) -> str: [ # demo seed data uses trusted config and generated timestamps f"INSERT INTO {self._database}.products_current VALUES", # nosec B608 - "('PROD-001', 'Wireless Headphones', 'electronics', 79.99, 1, 142),", - "('PROD-002', 'Running Shoes', 'footwear', 129.99, 1, 58),", - "('PROD-003', 'Coffee Maker', 'kitchen', 49.99, 1, 203),", - "('PROD-004', 'Mechanical Keyboard', 'electronics', 149.99, 1, 37),", - "('PROD-005', 'Yoga Mat', 'fitness', 34.99, 1, 315),", - "('PROD-006', 'Backpack', 'accessories', 89.99, 1, 94),", - "('PROD-007', 'Water Bottle', 'fitness', 24.99, 1, 421),", - "('PROD-008', 'Desk Lamp', 'home', 44.99, 0, 0),", - "('PROD-009', 'Bluetooth Speaker', 'electronics', 59.99, 1, 167),", - "('PROD-010', 'Sunglasses', 'accessories', 119.99, 1, 72)", + "('PROD-001', 'Electric Kettle 1.7L 2200W', 'kettles', 2190.00, 0, 0),", + "('PROD-002', 'Air Fryer Grill 5.5L', 'grills', 5490.00, 1, 58),", + "('PROD-003', 'Immersion Blender Set 800W', 'blenders', 2490.00, 1, 203),", + "('PROD-004', 'Stand Mixer 5L Planetary', 'mixers', 6990.00, 1, 37),", + "('PROD-005', 'Drip Coffee Maker 1.2L', 'coffee', 3490.00, 1, 94),", + "('PROD-006', 'Waffle Maker Double', 'multibakers', 2290.00, 1, 142),", + "('PROD-007', 'Mini Chopper 500ml', 'choppers', 1490.00, 1, 315),", + "('PROD-008', 'Cold-Press Juicer', 'juicers', 4490.00, 1, 72),", + "('PROD-009', 'Digital Kitchen Scale 5kg', 'scales', 990.00, 1, 421),", + "('PROD-010', 'Vacuum Sealer Compact', 'vacuum-dry', 3290.00, 1, 167)", ] ), expect_json=False, @@ -471,14 +471,14 @@ def ts(delta: timedelta) -> str: [ # demo seed data uses trusted config and generated timestamps f"INSERT INTO {self._database}.orders_v2 VALUES", # nosec B608 - f"('ORD-20260404-1001', 'USR-10001', 'delivered', 159.98, 'USD', '{ts(timedelta(hours=2))}'),", - f"('ORD-20260404-1002', 'USR-10002', 'shipped', 129.99, 'USD', '{ts(timedelta(minutes=90))}'),", - f"('ORD-20260404-1003', 'USR-10001', 'confirmed', 249.97, 'USD', '{ts(timedelta(hours=1))}'),", - f"('ORD-20260404-1004', 'USR-10003', 'pending', 79.99, 'USD', '{ts(timedelta(minutes=45))}'),", - f"('ORD-20260404-1005', 'USR-10004', 'delivered', 89.99, 'USD', '{ts(timedelta(minutes=30))}'),", - f"('ORD-20260404-1006', 'USR-10002', 'cancelled', 34.99, 'USD', '{ts(timedelta(minutes=20))}'),", - f"('ORD-20260404-1007', 'USR-10005', 'confirmed', 179.98, 'USD', '{ts(timedelta(minutes=15))}'),", - f"('ORD-20260404-1008', 'USR-10003', 'pending', 59.99, 'USD', '{ts(timedelta(minutes=5))}')", + f"('ORD-20260404-1001', 'USR-10001', 'delivered', 76400.00, 'RUB', '{ts(timedelta(hours=2))}'),", + f"('ORD-20260404-1002', 'USR-10002', 'shipped', 48100.00, 'RUB', '{ts(timedelta(minutes=90))}'),", + f"('ORD-20260404-1003', 'USR-10003', 'confirmed', 2650.00, 'RUB', '{ts(timedelta(hours=1))}'),", + f"('ORD-20260404-1004', 'USR-10003', 'pending', 1890.00, 'RUB', '{ts(timedelta(minutes=45))}'),", + f"('ORD-20260404-1005', 'USR-10004', 'delivered', 2290.00, 'RUB', '{ts(timedelta(minutes=30))}'),", + f"('ORD-20260404-1006', 'USR-10004', 'cancelled', 1590.00, 'RUB', '{ts(timedelta(minutes=20))}'),", + f"('ORD-20260404-1007', 'USR-10005', 'confirmed', 2990.00, 'RUB', '{ts(timedelta(minutes=15))}'),", + f"('ORD-20260404-1008', 'USR-10005', 'pending', 3990.00, 'RUB', '{ts(timedelta(minutes=5))}')", ] ), expect_json=False, @@ -489,11 +489,11 @@ def ts(delta: timedelta) -> str: [ # demo seed data uses trusted config and generated timestamps f"INSERT INTO {self._database}.users_enriched VALUES", # nosec B608 - f"('USR-10001', 15, 2340.50, '{ts(timedelta(days=180))}', '{ts(timedelta(hours=1))}', 'electronics'),", - f"('USR-10002', 8, 890.20, '{ts(timedelta(days=90))}', '{ts(timedelta(minutes=20))}', 'footwear'),", - f"('USR-10003', 3, 210.00, '{ts(timedelta(days=30))}', '{ts(timedelta(minutes=5))}', 'electronics'),", - f"('USR-10004', 22, 4100.75, '{ts(timedelta(days=365))}', '{ts(timedelta(minutes=30))}', 'accessories'),", - f"('USR-10005', 1, 179.98, '{ts(timedelta(days=1))}', '{ts(timedelta(minutes=15))}', 'electronics')", + f"('USR-10001', 34, 1200000.00, '{ts(timedelta(days=365))}', '{ts(timedelta(hours=2))}', 'grills'),", + f"('USR-10002', 15, 460000.00, '{ts(timedelta(days=270))}', '{ts(timedelta(minutes=90))}', 'coffee'),", + f"('USR-10003', 4, 8900.00, '{ts(timedelta(days=60))}', '{ts(timedelta(minutes=45))}', 'choppers'),", + f"('USR-10004', 6, 15800.00, '{ts(timedelta(days=120))}', '{ts(timedelta(minutes=20))}', 'blenders'),", + f"('USR-10005', 3, 28500.00, '{ts(timedelta(days=10))}', '{ts(timedelta(minutes=5))}', 'vacuum-dry')", ] ), expect_json=False, @@ -504,8 +504,8 @@ def ts(delta: timedelta) -> str: [ # demo seed data uses trusted config and generated timestamps f"INSERT INTO {self._database}.sessions_aggregated VALUES", # nosec B608 - f"('SES-a1b2c3', 'USR-10001', '{ts(timedelta(hours=2))}', '{ts(timedelta(minutes=100))}', 1200, 14, 6, 'checkout', 1),", - f"('SES-d4e5f6', 'USR-10002', '{ts(timedelta(minutes=90))}', '{ts(timedelta(minutes=70))}', 1200, 8, 4, 'add_to_cart', 0),", + f"('SES-a1b2c3', 'USR-10005', '{ts(timedelta(hours=2))}', '{ts(timedelta(minutes=100))}', 1200, 14, 6, 'checkout', 1),", + f"('SES-d4e5f6', 'USR-10004', '{ts(timedelta(minutes=90))}', '{ts(timedelta(minutes=70))}', 1200, 8, 4, 'add_to_cart', 0),", f"('SES-g7h8i9', NULL, '{ts(timedelta(minutes=60))}', '{ts(timedelta(minutes=58))}', 120, 2, 2, 'bounce', 0),", f"('SES-j1k2l3', 'USR-10003', '{ts(timedelta(minutes=45))}', '{ts(timedelta(minutes=20))}', 1500, 11, 5, 'checkout', 1),", f"('SES-m4n5o6', 'USR-10004', '{ts(timedelta(minutes=30))}', '{ts(timedelta(minutes=15))}', 900, 6, 3, 'product_view', 0),", diff --git a/src/serving/backends/duckdb_backend.py b/src/serving/backends/duckdb_backend.py index 6799be46..1bbaaf8e 100644 --- a/src/serving/backends/duckdb_backend.py +++ b/src/serving/backends/duckdb_backend.py @@ -126,7 +126,7 @@ def initialize_demo_data(self) -> None: user_id VARCHAR, status VARCHAR, total_amount DECIMAL(10,2), - currency VARCHAR DEFAULT 'USD', + currency VARCHAR DEFAULT 'RUB', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """) @@ -192,59 +192,59 @@ def initialize_demo_data(self) -> None: self._conn.execute(""" INSERT INTO products_current VALUES - ('PROD-001', 'Wireless Headphones', 'electronics', 79.99, TRUE, 142), - ('PROD-002', 'Running Shoes', 'footwear', 129.99, TRUE, 58), - ('PROD-003', 'Coffee Maker', 'kitchen', 49.99, TRUE, 203), - ('PROD-004', 'Mechanical Keyboard', 'electronics', 149.99, TRUE, 37), - ('PROD-005', 'Yoga Mat', 'fitness', 34.99, TRUE, 315), - ('PROD-006', 'Backpack', 'accessories', 89.99, TRUE, 94), - ('PROD-007', 'Water Bottle', 'fitness', 24.99, TRUE, 421), - ('PROD-008', 'Desk Lamp', 'home', 44.99, FALSE, 0), - ('PROD-009', 'Bluetooth Speaker', 'electronics', 59.99, TRUE, 167), - ('PROD-010', 'Sunglasses', 'accessories', 119.99, TRUE, 72) + ('PROD-001', 'Electric Kettle 1.7L 2200W', 'kettles', 2190.00, FALSE, 0), + ('PROD-002', 'Air Fryer Grill 5.5L', 'grills', 5490.00, TRUE, 58), + ('PROD-003', 'Immersion Blender Set 800W', 'blenders', 2490.00, TRUE, 203), + ('PROD-004', 'Stand Mixer 5L Planetary', 'mixers', 6990.00, TRUE, 37), + ('PROD-005', 'Drip Coffee Maker 1.2L', 'coffee', 3490.00, TRUE, 94), + ('PROD-006', 'Waffle Maker Double', 'multibakers', 2290.00, TRUE, 142), + ('PROD-007', 'Mini Chopper 500ml', 'choppers', 1490.00, TRUE, 315), + ('PROD-008', 'Cold-Press Juicer', 'juicers', 4490.00, TRUE, 72), + ('PROD-009', 'Digital Kitchen Scale 5kg', 'scales', 990.00, TRUE, 421), + ('PROD-010', 'Vacuum Sealer Compact', 'vacuum-dry', 3290.00, TRUE, 167) """) self._conn.execute(""" INSERT INTO orders_v2 VALUES ('ORD-20260404-1001', 'USR-10001', 'delivered', - 159.98, 'USD', NOW() - INTERVAL '2 hours'), + 76400.00, 'RUB', NOW() - INTERVAL '2 hours'), ('ORD-20260404-1002', 'USR-10002', 'shipped', - 129.99, 'USD', NOW() - INTERVAL '90 minutes'), - ('ORD-20260404-1003', 'USR-10001', 'confirmed', - 249.97, 'USD', NOW() - INTERVAL '1 hour'), + 48100.00, 'RUB', NOW() - INTERVAL '90 minutes'), + ('ORD-20260404-1003', 'USR-10003', 'confirmed', + 2650.00, 'RUB', NOW() - INTERVAL '1 hour'), ('ORD-20260404-1004', 'USR-10003', 'pending', - 79.99, 'USD', NOW() - INTERVAL '45 minutes'), + 1890.00, 'RUB', NOW() - INTERVAL '45 minutes'), ('ORD-20260404-1005', 'USR-10004', 'delivered', - 89.99, 'USD', NOW() - INTERVAL '30 minutes'), - ('ORD-20260404-1006', 'USR-10002', 'cancelled', - 34.99, 'USD', NOW() - INTERVAL '20 minutes'), + 2290.00, 'RUB', NOW() - INTERVAL '30 minutes'), + ('ORD-20260404-1006', 'USR-10004', 'cancelled', + 1590.00, 'RUB', NOW() - INTERVAL '20 minutes'), ('ORD-20260404-1007', 'USR-10005', 'confirmed', - 179.98, 'USD', NOW() - INTERVAL '15 minutes'), - ('ORD-20260404-1008', 'USR-10003', 'pending', - 59.99, 'USD', NOW() - INTERVAL '5 minutes') + 2990.00, 'RUB', NOW() - INTERVAL '15 minutes'), + ('ORD-20260404-1008', 'USR-10005', 'pending', + 3990.00, 'RUB', NOW() - INTERVAL '5 minutes') """) self._conn.execute(""" INSERT INTO users_enriched VALUES - ('USR-10001', 15, 2340.50, NOW() - INTERVAL '180 days', - NOW() - INTERVAL '1 hour', 'electronics'), - ('USR-10002', 8, 890.20, NOW() - INTERVAL '90 days', - NOW() - INTERVAL '20 minutes', 'footwear'), - ('USR-10003', 3, 210.00, NOW() - INTERVAL '30 days', - NOW() - INTERVAL '5 minutes', 'electronics'), - ('USR-10004', 22, 4100.75, NOW() - INTERVAL '365 days', - NOW() - INTERVAL '30 minutes', 'accessories'), - ('USR-10005', 1, 179.98, NOW() - INTERVAL '1 day', - NOW() - INTERVAL '15 minutes', 'electronics') + ('USR-10001', 34, 1200000.00, NOW() - INTERVAL '365 days', + NOW() - INTERVAL '2 hours', 'grills'), + ('USR-10002', 15, 460000.00, NOW() - INTERVAL '270 days', + NOW() - INTERVAL '90 minutes', 'coffee'), + ('USR-10003', 4, 8900.00, NOW() - INTERVAL '60 days', + NOW() - INTERVAL '45 minutes', 'choppers'), + ('USR-10004', 6, 15800.00, NOW() - INTERVAL '120 days', + NOW() - INTERVAL '20 minutes', 'blenders'), + ('USR-10005', 3, 28500.00, NOW() - INTERVAL '10 days', + NOW() - INTERVAL '5 minutes', 'vacuum-dry') """) self._conn.execute(""" INSERT INTO sessions_aggregated VALUES - ('SES-a1b2c3', 'USR-10001', + ('SES-a1b2c3', 'USR-10005', NOW() - INTERVAL '2 hours', NOW() - INTERVAL '100 minutes', 1200, 14, 6, 'checkout', TRUE), - ('SES-d4e5f6', 'USR-10002', + ('SES-d4e5f6', 'USR-10004', NOW() - INTERVAL '90 minutes', NOW() - INTERVAL '70 minutes', 1200, 8, 4, 'add_to_cart', FALSE), diff --git a/src/serving/semantic_layer/catalog.py b/src/serving/semantic_layer/catalog.py index ee4d67c1..c62ffff9 100644 --- a/src/serving/semantic_layer/catalog.py +++ b/src/serving/semantic_layer/catalog.py @@ -63,7 +63,7 @@ def _register_defaults(self) -> None: "WHERE status != 'cancelled' " "AND created_at >= NOW() - INTERVAL '{window}'" ), - unit="USD", + unit="RUB", contract_version=self.contract_registry.latest_contract_version("metric.revenue"), source_events=["order.created", "order.updated", "order.cancelled"], source_table="orders_v2", @@ -103,7 +103,7 @@ def _register_defaults(self) -> None: "WHERE status != 'cancelled' " "AND created_at >= NOW() - INTERVAL '{window}'" ), - unit="USD", + unit="RUB", contract_version=self.contract_registry.latest_contract_version( "metric.avg_order_value" ), diff --git a/src/serving/semantic_layer/search_index.py b/src/serving/semantic_layer/search_index.py index a9465a94..a1744143 100644 --- a/src/serving/semantic_layer/search_index.py +++ b/src/serving/semantic_layer/search_index.py @@ -267,13 +267,13 @@ def _entity_snippet(self, entity: EntityDefinition, payload: dict) -> str: stock_status = "in stock" if payload.get("in_stock") else "out of stock" return ( f"Product {payload.get('name')} ({payload.get('product_id')}) " - f"category {payload.get('category')} price {payload.get('price')} USD " + f"category {payload.get('category')} price {payload.get('price')} RUB " f"{stock_status}" ) if entity.name == "user": return ( f"User {payload.get('user_id')} with {payload.get('total_orders')} orders " - f"spent {payload.get('total_spent')} USD " + f"spent {payload.get('total_spent')} RUB " f"prefers {payload.get('preferred_category')}" ) if entity.name == "session": diff --git a/tests/integration/test_batch.py b/tests/integration/test_batch.py index 8f028f1e..c6e94c6a 100644 --- a/tests/integration/test_batch.py +++ b/tests/integration/test_batch.py @@ -102,7 +102,7 @@ def test_batch_returns_results_for_mixed_request_types(client): assert "_last_updated" not in entity_result["data"] assert metric_result["status"] == "ok" - assert metric_result["data"]["unit"] == "USD" + assert metric_result["data"]["unit"] == "RUB" assert metric_result["data"]["value"] >= 0 assert query_result["status"] == "ok" diff --git a/tests/integration/test_pagination.py b/tests/integration/test_pagination.py index 5362b0b4..349a3845 100644 --- a/tests/integration/test_pagination.py +++ b/tests/integration/test_pagination.py @@ -25,10 +25,10 @@ def test_query_first_page_returns_rows_and_cursor(client: TestClient): data = response.json() assert [row["name"] for row in data["rows"]] == [ - "Mechanical Keyboard", - "Running Shoes", - "Sunglasses", - "Backpack", + "Stand Mixer 5L Planetary", + "Air Fryer Grill 5.5L", + "Cold-Press Juicer", + "Drip Coffee Maker 1.2L", ] assert data["answer"] == data["rows"] assert data["page_size"] == 4 @@ -57,10 +57,10 @@ def test_query_next_page_returns_following_rows(client: TestClient): data = response.json() assert [row["name"] for row in data["rows"]] == [ - "Wireless Headphones", - "Bluetooth Speaker", - "Coffee Maker", - "Desk Lamp", + "Vacuum Sealer Compact", + "Immersion Blender Set 800W", + "Waffle Maker Double", + "Electric Kettle 1.7L 2200W", ] assert data["page_size"] == 4 assert data["has_more"] is True @@ -95,8 +95,8 @@ def test_query_last_page_clears_cursor(client: TestClient): data = response.json() assert [row["name"] for row in data["rows"]] == [ - "Yoga Mat", - "Water Bottle", + "Mini Chopper 500ml", + "Digital Kitchen Scale 5kg", ] assert data["page_size"] == 4 assert data["has_more"] is False diff --git a/tests/integration/test_pipeline.py b/tests/integration/test_pipeline.py index 8f389b2f..0bc4f2d3 100644 --- a/tests/integration/test_pipeline.py +++ b/tests/integration/test_pipeline.py @@ -60,7 +60,7 @@ def test_metric_revenue_returns_real_data(self, client): assert response.status_code == 200 data = response.json() assert data["metric_name"] == "revenue" - assert data["unit"] == "USD" + assert data["unit"] == "RUB" assert data["value"] > 0 # demo data seeded def test_metric_error_rate(self, client): @@ -82,7 +82,7 @@ def test_entity_user_lookup(self, client): assert response.status_code == 200 data = response.json() assert data["entity_type"] == "user" - assert data["data"]["total_orders"] == 15 + assert data["data"]["total_orders"] == 34 def test_entity_not_found(self, client): response = client.get("/v1/entity/order/ORD-99999999-0000") @@ -158,7 +158,7 @@ def test_get_metric_with_data(self): engine = QueryEngine(catalog=catalog) result = engine.get_metric("revenue", window="24h") assert "value" in result - assert result["unit"] == "USD" + assert result["unit"] == "RUB" assert result["value"] > 0 # demo data def test_get_metric_error_rate(self): @@ -172,7 +172,7 @@ def test_get_entity_existing(self): engine = QueryEngine(catalog=catalog) result = engine.get_entity("product", "PROD-001") assert result is not None - assert result["name"] == "Wireless Headphones" + assert result["name"] == "Electric Kettle 1.7L 2200W" def test_get_entity_missing(self): catalog = DataCatalog() diff --git a/tests/unit/test_db_pool.py b/tests/unit/test_db_pool.py index 06f1f266..c5179cc8 100644 --- a/tests/unit/test_db_pool.py +++ b/tests/unit/test_db_pool.py @@ -174,7 +174,7 @@ def test_query_engine_uses_pool_for_reads(tmp_path): entity = engine.get_entity("product", "PROD-001") assert entity is not None - assert entity["name"] == "Wireless Headphones" + assert entity["name"] == "Electric Kettle 1.7L 2200W" assert engine._conn is pool.write_connection assert pool.stats()["read_in_use"] == 0 finally: diff --git a/tests/unit/test_query_engine_injection.py b/tests/unit/test_query_engine_injection.py index 89559db9..a08e429e 100644 --- a/tests/unit/test_query_engine_injection.py +++ b/tests/unit/test_query_engine_injection.py @@ -95,7 +95,7 @@ def test_get_metric_passes_as_of_anchor_as_query_params() -> None: result = engine.get_metric("revenue", window="24h", as_of=as_of) - assert result == {"value": 12.5, "unit": "USD"} + assert result == {"value": 12.5, "unit": "RUB"} assert backend.scalar.call_count == 1 args = backend.scalar.call_args.args assert len(args) == 2 diff --git a/tests/unit/test_query_engine_mixin_contracts.py b/tests/unit/test_query_engine_mixin_contracts.py index c327d141..d2889ac0 100644 --- a/tests/unit/test_query_engine_mixin_contracts.py +++ b/tests/unit/test_query_engine_mixin_contracts.py @@ -77,7 +77,7 @@ def test_get_metric_runs_against_minimal_host_contract(host: _MinimalQueryHost) result = host.get_metric("revenue") - assert result == {"value": 12.5, "unit": "USD"} + assert result == {"value": 12.5, "unit": "RUB"} host._backend.scalar.assert_called_once() diff --git a/tests/unit/test_query_package_logic.py b/tests/unit/test_query_package_logic.py index 4d90202a..0b86c141 100644 --- a/tests/unit/test_query_package_logic.py +++ b/tests/unit/test_query_package_logic.py @@ -193,7 +193,7 @@ def test_get_metric_literal_backend_inlines_as_of_anchor(literal_host: _Host) -> result = literal_host.get_metric("revenue", as_of=AWARE_TS) - assert result == {"value": 42.0, "unit": "USD"} + assert result == {"value": 42.0, "unit": "RUB"} sql = literal_host._backend.scalar.call_args.args[0] assert "NOW()" not in sql assert sql.count("AS TIMESTAMP") == 2 # anchor substitution + upper bound