SIENTIAPDE-1646
Update E2E test report and enhance drift analysis handling - Updated the E2E test report metrics to reflect the latest test results, showing 47 collected tests with all passing. - Removed outdated sections related to failed tests and their causes, streamlining the report. - Implemented a regression fix in the drift analysis to handle empty merged frames, ensuring workflows skip export when no drift metrics are available. - Enhanced the `insert_sample_data` and `insert_sample_prediction` functions to allow customizable timestamps for better test accuracy. - Refactored E2E tests to improve clarity and maintainability, particularly in handling repeat scenarios with distinct timestamps.
This commit is contained in:
@@ -80,7 +80,17 @@ async def start_and_await_workflow(client, workflow_run, input_data: dict, workf
|
||||
return await asyncio.wait_for(handle.result(), timeout=timeout)
|
||||
|
||||
|
||||
def insert_sample_data(postgres_engine: Engine, model_id: int, values: list[Any]) -> None:
|
||||
DEFAULT_BATCH_TIMESTAMP = '2024-01-01 12:00:00+00:00'
|
||||
DEFAULT_PREDICTION_HISTORY_TIMESTAMP = '2024-01-01 12:00:00+00:00'
|
||||
|
||||
|
||||
def insert_sample_data(
|
||||
postgres_engine: Engine,
|
||||
model_id: int,
|
||||
values: list[Any],
|
||||
*,
|
||||
data_timestamp: str = DEFAULT_BATCH_TIMESTAMP,
|
||||
) -> None:
|
||||
"""
|
||||
Replace laborious_data rows for a model_id with one row per value (sensor_1..n).
|
||||
|
||||
@@ -88,13 +98,15 @@ def insert_sample_data(postgres_engine: Engine, model_id: int, values: list[Any]
|
||||
postgres_engine: SQLAlchemy engine.
|
||||
model_id: Model id column value.
|
||||
values: Per-sensor values; use string 'NULL' for SQL NULL.
|
||||
data_timestamp: Timestamp and created_at for every inserted row; drives
|
||||
``last_timestamp`` on the MinIO/query payload (max row time).
|
||||
"""
|
||||
with postgres_engine.begin() as conn:
|
||||
conn.execute(text(f'DELETE FROM sientia_data.laborious_data WHERE model_id = {model_id}'))
|
||||
values_sql = []
|
||||
for i, value in enumerate(values):
|
||||
values_sql.append(f"""
|
||||
({model_id}, 'sensor_{i + 1}', {value}, '2024-01-01 12:00:00+00:00', '2024-01-01 12:00:00+00:00')
|
||||
({model_id}, 'sensor_{i + 1}', {value}, '{data_timestamp}', '{data_timestamp}')
|
||||
""")
|
||||
insert_sql = f"""
|
||||
INSERT INTO sientia_data.laborious_data (model_id, variable, value, timestamp, created_at)
|
||||
@@ -104,6 +116,88 @@ def insert_sample_data(postgres_engine: Engine, model_id: int, values: list[Any]
|
||||
conn.execute(text(insert_sql))
|
||||
|
||||
|
||||
def insert_sample_prediction(
|
||||
postgres_engine: Engine,
|
||||
model_id: int,
|
||||
*,
|
||||
prediction_timestamp: str = DEFAULT_PREDICTION_HISTORY_TIMESTAMP,
|
||||
) -> tuple[int, Decimal, Decimal, str]:
|
||||
"""
|
||||
Insert a single historical prediction row for REPEAT scenarios.
|
||||
|
||||
Args:
|
||||
postgres_engine: SQLAlchemy engine.
|
||||
model_id: Model id.
|
||||
prediction_timestamp: Row ``timestamp`` (unique with model_id in tests).
|
||||
|
||||
Return:
|
||||
tuple: (model_id, prediction, prediction_confidence, prediction_status) for assertions.
|
||||
"""
|
||||
with postgres_engine.begin() as conn:
|
||||
conn.execute(text(f'DELETE FROM sientia_data.predictions WHERE model_id = {model_id}'))
|
||||
insert_sql = f"""
|
||||
INSERT INTO sientia_data.predictions (
|
||||
model_id, timestamp, prediction, prediction_confidence, prediction_status, comments, response_time
|
||||
)
|
||||
VALUES (
|
||||
{model_id}, '{prediction_timestamp}', 10, 0, 'Good', '', 0.1
|
||||
)
|
||||
"""
|
||||
conn.execute(text(insert_sql))
|
||||
return (model_id, Decimal(10), Decimal(0), 'Good')
|
||||
|
||||
|
||||
def workflow_failure_message_chain(exc: BaseException) -> list[str]:
|
||||
"""
|
||||
Collect ``str()`` / ``message`` from an exception and its ``__cause__`` chain.
|
||||
|
||||
Args:
|
||||
exc: Root exception (e.g. from ``pytest.raises``).
|
||||
|
||||
Return:
|
||||
list[str]: Messages from root to innermost cause.
|
||||
"""
|
||||
messages: list[str] = []
|
||||
current: BaseException | None = exc
|
||||
while current is not None:
|
||||
messages.append(getattr(current, 'message', None) or str(current) or repr(current))
|
||||
current = current.__cause__
|
||||
return messages
|
||||
|
||||
|
||||
def assert_postgres_unique_violation_in_chain(exc: BaseException) -> None:
|
||||
"""
|
||||
Assert the exception chain mentions Postgres unique-constraint violation.
|
||||
|
||||
Args:
|
||||
exc: Workflow or activity error from Temporal.
|
||||
|
||||
Raises:
|
||||
AssertionError: If no link in the chain looks like UniqueViolation.
|
||||
"""
|
||||
chain = ' | '.join(workflow_failure_message_chain(exc))
|
||||
assert 'UniqueViolation' in chain or 'unique_model_id_timestamp' in chain, (
|
||||
f'Expected unique constraint violation in error chain, got: {chain}'
|
||||
)
|
||||
|
||||
|
||||
def assert_prediction_row_count(postgres_engine: Engine, model_id: int, expected: int) -> None:
|
||||
"""
|
||||
Assert how many prediction rows exist for a model_id.
|
||||
|
||||
Args:
|
||||
postgres_engine: SQLAlchemy engine.
|
||||
model_id: Model id filter.
|
||||
expected: Expected row count.
|
||||
"""
|
||||
with postgres_engine.connect() as conn:
|
||||
n = conn.execute(
|
||||
text('SELECT COUNT(*) FROM sientia_data.predictions WHERE model_id = :m'),
|
||||
{'m': model_id},
|
||||
).scalar()
|
||||
assert n == expected, f'Expected {expected} prediction rows, got {n}'
|
||||
|
||||
|
||||
def assert_prediction(
|
||||
postgres_engine: Engine,
|
||||
model_id: int,
|
||||
|
||||
Reference in New Issue
Block a user