032: fix tests — validate_target_table_schema became async (add await + AsyncMock)

All test methods calling validate_target_table_schema now async def + await.
Mocked async methods (resolve_database_id, execute_and_poll) use AsyncMock
instead of MagicMock since await on MagicMock raises TypeError.
This commit is contained in:
2026-06-05 00:18:13 +03:00
parent c2578facdb
commit 58e994cd75
2 changed files with 65 additions and 65 deletions

View File

@@ -11,7 +11,7 @@
import pytest import pytest
from typing import Any from typing import Any
from unittest.mock import MagicMock, patch from unittest.mock import AsyncMock, MagicMock, patch
from src.plugins.translate.service_utils import _extract_dialect from src.plugins.translate.service_utils import _extract_dialect
from src.plugins.translate.service_datasource import ( from src.plugins.translate.service_datasource import (
@@ -648,7 +648,7 @@ class TestSchemaValidationDialectRouting:
# region test_clickhouse_uses_system_columns [TYPE Function] # region test_clickhouse_uses_system_columns [TYPE Function]
# @PURPOSE: ClickHouse backend generates system.columns query. # @PURPOSE: ClickHouse backend generates system.columns query.
@patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor") @patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor")
def test_clickhouse_uses_system_columns(self, mock_executor) -> None: async def test_clickhouse_uses_system_columns(self, mock_executor) -> None:
from src.schemas.translate import TargetSchemaValidationRequest from src.schemas.translate import TargetSchemaValidationRequest
from src.plugins.translate.service_target_schema import validate_target_table_schema from src.plugins.translate.service_target_schema import validate_target_table_schema
@@ -663,10 +663,10 @@ class TestSchemaValidationDialectRouting:
config_manager = MagicMock() config_manager = MagicMock()
instance = mock_executor.return_value instance = mock_executor.return_value
instance.resolve_database_id.return_value = None instance.resolve_database_id = AsyncMock(return_value=None)
instance.get_database_backend.return_value = "clickhouse" instance.get_database_backend.return_value = "clickhouse"
instance.get_database_name.return_value = "test_ch" instance.get_database_name.return_value = "test_ch"
instance.execute_and_poll.return_value = { instance.execute_and_poll = AsyncMock(return_value={
"status": "success", "status": "success",
"raw_response": { "raw_response": {
"data": [ "data": [
@@ -676,9 +676,9 @@ class TestSchemaValidationDialectRouting:
{"name": "is_original", "type": "UInt8"}, {"name": "is_original", "type": "UInt8"},
], ],
}, },
} })
validate_target_table_schema(req, config_manager) await validate_target_table_schema(req, config_manager)
# Verify the SQL query used system.columns # Verify the SQL query used system.columns
call_args = instance.execute_and_poll.call_args call_args = instance.execute_and_poll.call_args
@@ -690,7 +690,7 @@ class TestSchemaValidationDialectRouting:
# region test_postgresql_uses_information_schema [TYPE Function] # region test_postgresql_uses_information_schema [TYPE Function]
# @PURPOSE: PostgreSQL backend generates information_schema.columns query. # @PURPOSE: PostgreSQL backend generates information_schema.columns query.
@patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor") @patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor")
def test_postgresql_uses_information_schema(self, mock_executor) -> None: async def test_postgresql_uses_information_schema(self, mock_executor) -> None:
from src.schemas.translate import TargetSchemaValidationRequest from src.schemas.translate import TargetSchemaValidationRequest
from src.plugins.translate.service_target_schema import validate_target_table_schema from src.plugins.translate.service_target_schema import validate_target_table_schema
@@ -705,10 +705,10 @@ class TestSchemaValidationDialectRouting:
config_manager = MagicMock() config_manager = MagicMock()
instance = mock_executor.return_value instance = mock_executor.return_value
instance.resolve_database_id.return_value = None instance.resolve_database_id = AsyncMock(return_value=None)
instance.get_database_backend.return_value = "postgresql" instance.get_database_backend.return_value = "postgresql"
instance.get_database_name.return_value = "test_pg" instance.get_database_name.return_value = "test_pg"
instance.execute_and_poll.return_value = { instance.execute_and_poll = AsyncMock(return_value={
"status": "success", "status": "success",
"raw_response": { "raw_response": {
"data": [ "data": [
@@ -718,9 +718,9 @@ class TestSchemaValidationDialectRouting:
{"column_name": "is_original", "data_type": "boolean"}, {"column_name": "is_original", "data_type": "boolean"},
], ],
}, },
} })
validate_target_table_schema(req, config_manager) await validate_target_table_schema(req, config_manager)
call_args = instance.execute_and_poll.call_args call_args = instance.execute_and_poll.call_args
sql = call_args.kwargs.get("sql") or call_args.args[0] sql = call_args.kwargs.get("sql") or call_args.args[0]
@@ -731,7 +731,7 @@ class TestSchemaValidationDialectRouting:
# region test_clickhousedb_normalized_to_clickhouse [TYPE Function] # region test_clickhousedb_normalized_to_clickhouse [TYPE Function]
# @PURPOSE: "clickhousedb" backend is normalized to clickhouse -> uses system.columns. # @PURPOSE: "clickhousedb" backend is normalized to clickhouse -> uses system.columns.
@patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor") @patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor")
def test_clickhousedb_normalized_to_clickhouse(self, mock_executor) -> None: async def test_clickhousedb_normalized_to_clickhouse(self, mock_executor) -> None:
from src.schemas.translate import TargetSchemaValidationRequest from src.schemas.translate import TargetSchemaValidationRequest
from src.plugins.translate.service_target_schema import validate_target_table_schema from src.plugins.translate.service_target_schema import validate_target_table_schema
@@ -746,10 +746,10 @@ class TestSchemaValidationDialectRouting:
config_manager = MagicMock() config_manager = MagicMock()
instance = mock_executor.return_value instance = mock_executor.return_value
instance.resolve_database_id.return_value = None instance.resolve_database_id = AsyncMock(return_value=None)
instance.get_database_backend.return_value = "clickhousedb" instance.get_database_backend.return_value = "clickhousedb"
instance.get_database_name.return_value = "test_ch" instance.get_database_name.return_value = "test_ch"
instance.execute_and_poll.return_value = { instance.execute_and_poll = AsyncMock(return_value={
"status": "success", "status": "success",
"raw_response": { "raw_response": {
"data": [ "data": [
@@ -759,9 +759,9 @@ class TestSchemaValidationDialectRouting:
{"name": "is_original", "type": "UInt8"}, {"name": "is_original", "type": "UInt8"},
], ],
}, },
} })
validate_target_table_schema(req, config_manager) await validate_target_table_schema(req, config_manager)
call_args = instance.execute_and_poll.call_args call_args = instance.execute_and_poll.call_args
sql = call_args.kwargs.get("sql") or call_args.args[0] sql = call_args.kwargs.get("sql") or call_args.args[0]
@@ -771,7 +771,7 @@ class TestSchemaValidationDialectRouting:
# region test_greenplum_normalized_to_postgresql [TYPE Function] # region test_greenplum_normalized_to_postgresql [TYPE Function]
# @PURPOSE: "greenplum" backend is normalized to postgresql -> uses information_schema. # @PURPOSE: "greenplum" backend is normalized to postgresql -> uses information_schema.
@patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor") @patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor")
def test_greenplum_normalized_to_postgresql(self, mock_executor) -> None: async def test_greenplum_normalized_to_postgresql(self, mock_executor) -> None:
from src.schemas.translate import TargetSchemaValidationRequest from src.schemas.translate import TargetSchemaValidationRequest
from src.plugins.translate.service_target_schema import validate_target_table_schema from src.plugins.translate.service_target_schema import validate_target_table_schema
@@ -786,10 +786,10 @@ class TestSchemaValidationDialectRouting:
config_manager = MagicMock() config_manager = MagicMock()
instance = mock_executor.return_value instance = mock_executor.return_value
instance.resolve_database_id.return_value = None instance.resolve_database_id = AsyncMock(return_value=None)
instance.get_database_backend.return_value = "greenplum" instance.get_database_backend.return_value = "greenplum"
instance.get_database_name.return_value = "test_gp" instance.get_database_name.return_value = "test_gp"
instance.execute_and_poll.return_value = { instance.execute_and_poll = AsyncMock(return_value={
"status": "success", "status": "success",
"raw_response": { "raw_response": {
"data": [ "data": [
@@ -799,9 +799,9 @@ class TestSchemaValidationDialectRouting:
{"name": "is_original", "type": "boolean"}, {"name": "is_original", "type": "boolean"},
], ],
}, },
} })
validate_target_table_schema(req, config_manager) await validate_target_table_schema(req, config_manager)
call_args = instance.execute_and_poll.call_args call_args = instance.execute_and_poll.call_args
sql = call_args.kwargs.get("sql") or call_args.args[0] sql = call_args.kwargs.get("sql") or call_args.args[0]
@@ -811,7 +811,7 @@ class TestSchemaValidationDialectRouting:
# region test_redshift_uses_information_schema [TYPE Function] # region test_redshift_uses_information_schema [TYPE Function]
# @PURPOSE: Redshift uses information_schema (it's PostgreSQL-derived). # @PURPOSE: Redshift uses information_schema (it's PostgreSQL-derived).
@patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor") @patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor")
def test_redshift_uses_information_schema(self, mock_executor) -> None: async def test_redshift_uses_information_schema(self, mock_executor) -> None:
from src.schemas.translate import TargetSchemaValidationRequest from src.schemas.translate import TargetSchemaValidationRequest
from src.plugins.translate.service_target_schema import validate_target_table_schema from src.plugins.translate.service_target_schema import validate_target_table_schema
@@ -826,10 +826,10 @@ class TestSchemaValidationDialectRouting:
config_manager = MagicMock() config_manager = MagicMock()
instance = mock_executor.return_value instance = mock_executor.return_value
instance.resolve_database_id.return_value = None instance.resolve_database_id = AsyncMock(return_value=None)
instance.get_database_backend.return_value = "redshift" instance.get_database_backend.return_value = "redshift"
instance.get_database_name.return_value = "test_rs" instance.get_database_name.return_value = "test_rs"
instance.execute_and_poll.return_value = { instance.execute_and_poll = AsyncMock(return_value={
"status": "success", "status": "success",
"raw_response": { "raw_response": {
"data": [ "data": [
@@ -839,9 +839,9 @@ class TestSchemaValidationDialectRouting:
{"column_name": "is_original", "data_type": "boolean"}, {"column_name": "is_original", "data_type": "boolean"},
], ],
}, },
} })
validate_target_table_schema(req, config_manager) await validate_target_table_schema(req, config_manager)
call_args = instance.execute_and_poll.call_args call_args = instance.execute_and_poll.call_args
sql = call_args.kwargs.get("sql") or call_args.args[0] sql = call_args.kwargs.get("sql") or call_args.args[0]
@@ -851,7 +851,7 @@ class TestSchemaValidationDialectRouting:
# region test_case_insensitive_backend_normalization [TYPE Function] # region test_case_insensitive_backend_normalization [TYPE Function]
# @PURPOSE: Backend normalization is case-insensitive. # @PURPOSE: Backend normalization is case-insensitive.
@patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor") @patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor")
def test_case_insensitive_backend_normalization(self, mock_executor) -> None: async def test_case_insensitive_backend_normalization(self, mock_executor) -> None:
from src.schemas.translate import TargetSchemaValidationRequest from src.schemas.translate import TargetSchemaValidationRequest
from src.plugins.translate.service_target_schema import validate_target_table_schema from src.plugins.translate.service_target_schema import validate_target_table_schema
@@ -866,10 +866,10 @@ class TestSchemaValidationDialectRouting:
config_manager = MagicMock() config_manager = MagicMock()
instance = mock_executor.return_value instance = mock_executor.return_value
instance.resolve_database_id.return_value = None instance.resolve_database_id = AsyncMock(return_value=None)
instance.get_database_backend.return_value = "ClickHouseDB" instance.get_database_backend.return_value = "ClickHouseDB"
instance.get_database_name.return_value = "test_ch" instance.get_database_name.return_value = "test_ch"
instance.execute_and_poll.return_value = { instance.execute_and_poll = AsyncMock(return_value={
"status": "success", "status": "success",
"raw_response": { "raw_response": {
"data": [ "data": [
@@ -879,9 +879,9 @@ class TestSchemaValidationDialectRouting:
{"name": "is_original", "type": "UInt8"}, {"name": "is_original", "type": "UInt8"},
], ],
}, },
} })
validate_target_table_schema(req, config_manager) await validate_target_table_schema(req, config_manager)
call_args = instance.execute_and_poll.call_args call_args = instance.execute_and_poll.call_args
sql = call_args.kwargs.get("sql") or call_args.args[0] sql = call_args.kwargs.get("sql") or call_args.args[0]

View File

@@ -9,7 +9,7 @@
# @TEST_CONTRACT validate_target_table_schema -> TargetSchemaValidationResponse # @TEST_CONTRACT validate_target_table_schema -> TargetSchemaValidationResponse
import pytest import pytest
from unittest.mock import MagicMock, patch from unittest.mock import AsyncMock, MagicMock, patch
from src.plugins.translate.service_target_schema import ( from src.plugins.translate.service_target_schema import (
_build_expected_columns, _build_expected_columns,
@@ -271,16 +271,16 @@ class TestParseSqlLabResult:
class TestValidateTargetTableSchema: class TestValidateTargetTableSchema:
@patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor") @patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor")
def test_all_columns_present(self, mock_executor, build_request) -> None: async def test_all_columns_present(self, mock_executor, build_request) -> None:
"""Все ожидаемые колонки присутствуют в таблице.""" """Все ожидаемые колонки присутствуют в таблице."""
req = build_request() req = build_request()
config_manager = MagicMock() config_manager = MagicMock()
instance = mock_executor.return_value instance = mock_executor.return_value
instance.resolve_database_id.return_value = None instance.resolve_database_id = AsyncMock(return_value=None)
instance.get_database_backend.return_value = "postgresql" instance.get_database_backend.return_value = "postgresql"
instance.get_database_name.return_value = "test_db" instance.get_database_name.return_value = "test_db"
instance.execute_and_poll.return_value = { instance.execute_and_poll = AsyncMock(return_value={
"status": "success", "status": "success",
"raw_response": { "raw_response": {
"columns": [{"name": "column_name"}, {"name": "data_type"}], "columns": [{"name": "column_name"}, {"name": "data_type"}],
@@ -291,9 +291,9 @@ class TestValidateTargetTableSchema:
{"column_name": "is_original", "data_type": "boolean"}, {"column_name": "is_original", "data_type": "boolean"},
], ],
}, },
} })
response = validate_target_table_schema(req, config_manager) response = await validate_target_table_schema(req, config_manager)
assert response.table_exists is True assert response.table_exists is True
assert response.error is None assert response.error is None
assert response.all_present is True assert response.all_present is True
@@ -304,16 +304,16 @@ class TestValidateTargetTableSchema:
assert response.database_backend == "postgresql" assert response.database_backend == "postgresql"
@patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor") @patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor")
def test_missing_columns(self, mock_executor, build_request) -> None: async def test_missing_columns(self, mock_executor, build_request) -> None:
"""В таблице не хватает некоторых ожидаемых колонок.""" """В таблице не хватает некоторых ожидаемых колонок."""
req = build_request() req = build_request()
config_manager = MagicMock() config_manager = MagicMock()
instance = mock_executor.return_value instance = mock_executor.return_value
instance.resolve_database_id.return_value = None instance.resolve_database_id = AsyncMock(return_value=None)
instance.get_database_backend.return_value = "postgresql" instance.get_database_backend.return_value = "postgresql"
instance.get_database_name.return_value = "test_db" instance.get_database_name.return_value = "test_db"
instance.execute_and_poll.return_value = { instance.execute_and_poll = AsyncMock(return_value={
"status": "success", "status": "success",
"raw_response": { "raw_response": {
"columns": [{"name": "column_name"}], "columns": [{"name": "column_name"}],
@@ -322,9 +322,9 @@ class TestValidateTargetTableSchema:
{"column_name": "context"}, {"column_name": "context"},
], ],
}, },
} })
response = validate_target_table_schema(req, config_manager) response = await validate_target_table_schema(req, config_manager)
assert response.table_exists is True assert response.table_exists is True
assert response.all_present is False assert response.all_present is False
missing_names = {c.name for c in response.missing_columns} missing_names = {c.name for c in response.missing_columns}
@@ -333,7 +333,7 @@ class TestValidateTargetTableSchema:
assert "id" not in missing_names assert "id" not in missing_names
@patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor") @patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor")
def test_clickhouse_describe_table(self, mock_executor, build_request) -> None: async def test_clickhouse_describe_table(self, mock_executor, build_request) -> None:
"""ClickHouse использует DESCRIBE TABLE — другой формат ответа.""" """ClickHouse использует DESCRIBE TABLE — другой формат ответа."""
req = build_request( req = build_request(
target_key_cols=["report_date", "document_number"], target_key_cols=["report_date", "document_number"],
@@ -345,10 +345,10 @@ class TestValidateTargetTableSchema:
config_manager = MagicMock() config_manager = MagicMock()
instance = mock_executor.return_value instance = mock_executor.return_value
instance.resolve_database_id.return_value = None instance.resolve_database_id = AsyncMock(return_value=None)
instance.get_database_backend.return_value = "clickhouse" instance.get_database_backend.return_value = "clickhouse"
instance.get_database_name.return_value = "test_clickhouse" instance.get_database_name.return_value = "test_clickhouse"
instance.execute_and_poll.return_value = { instance.execute_and_poll = AsyncMock(return_value={
"status": "success", "status": "success",
"raw_response": { "raw_response": {
"columns": [{"name": "name"}, {"name": "type"}], "columns": [{"name": "name"}, {"name": "type"}],
@@ -363,9 +363,9 @@ class TestValidateTargetTableSchema:
{"name": "is_original", "type": "UInt8"}, {"name": "is_original", "type": "UInt8"},
], ],
}, },
} })
response = validate_target_table_schema(req, config_manager) response = await validate_target_table_schema(req, config_manager)
assert response.table_exists is True assert response.table_exists is True
assert response.error is None assert response.error is None
assert response.all_present is True assert response.all_present is True
@@ -375,85 +375,85 @@ class TestValidateTargetTableSchema:
assert response.database_backend == "clickhouse" assert response.database_backend == "clickhouse"
@patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor") @patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor")
def test_superset_failed_status(self, mock_executor, build_request) -> None: async def test_superset_failed_status(self, mock_executor, build_request) -> None:
"""Superset возвращает failed статус.""" """Superset возвращает failed статус."""
req = build_request() req = build_request()
config_manager = MagicMock() config_manager = MagicMock()
instance = mock_executor.return_value instance = mock_executor.return_value
instance.resolve_database_id.return_value = None instance.resolve_database_id = AsyncMock(return_value=None)
instance.get_database_backend.return_value = "postgresql" instance.get_database_backend.return_value = "postgresql"
instance.get_database_name.return_value = "test_db" instance.get_database_name.return_value = "test_db"
instance.execute_and_poll.return_value = { instance.execute_and_poll = AsyncMock(return_value={
"status": "failed", "status": "failed",
"error_message": "Query timeout", "error_message": "Query timeout",
} })
response = validate_target_table_schema(req, config_manager) response = await validate_target_table_schema(req, config_manager)
assert response.table_exists is False assert response.table_exists is False
assert response.error is not None assert response.error is not None
assert "Query timeout" in response.error assert "Query timeout" in response.error
assert response.all_present is False assert response.all_present is False
@patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor") @patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor")
def test_executor_exception(self, mock_executor, build_request) -> None: async def test_executor_exception(self, mock_executor, build_request) -> None:
"""Executor бросает исключение.""" """Executor бросает исключение."""
req = build_request() req = build_request()
config_manager = MagicMock() config_manager = MagicMock()
instance = mock_executor.return_value instance = mock_executor.return_value
instance.resolve_database_id.return_value = None instance.resolve_database_id = AsyncMock(return_value=None)
instance.get_database_backend.return_value = "postgresql" instance.get_database_backend.return_value = "postgresql"
instance.get_database_name.return_value = "test_db" instance.get_database_name.return_value = "test_db"
instance.execute_and_poll.side_effect = ConnectionError("Superset API unavailable") instance.execute_and_poll = AsyncMock(side_effect=ConnectionError("Superset API unavailable"))
response = validate_target_table_schema(req, config_manager) response = await validate_target_table_schema(req, config_manager)
assert response.table_exists is False assert response.table_exists is False
assert response.error is not None assert response.error is not None
assert "Superset API unavailable" in response.error assert "Superset API unavailable" in response.error
assert response.all_present is False assert response.all_present is False
def test_sql_injection_table_name(self, build_request) -> None: async def test_sql_injection_table_name(self, build_request) -> None:
"""Невалидное имя таблицы с пробелом — ошибка.""" """Невалидное имя таблицы с пробелом — ошибка."""
req = build_request(target_table="my table; DROP TABLE students; --") req = build_request(target_table="my table; DROP TABLE students; --")
config_manager = MagicMock() config_manager = MagicMock()
response = validate_target_table_schema(req, config_manager) response = await validate_target_table_schema(req, config_manager)
assert response.table_exists is False assert response.table_exists is False
assert response.error is not None assert response.error is not None
assert "Invalid target table name" in response.error assert "Invalid target table name" in response.error
assert response.all_present is False assert response.all_present is False
def test_sql_injection_schema_name(self, build_request) -> None: async def test_sql_injection_schema_name(self, build_request) -> None:
"""Невалидное имя схемы с DROP — ошибка.""" """Невалидное имя схемы с DROP — ошибка."""
req = build_request(target_schema="public; DROP TABLE students; --") req = build_request(target_schema="public; DROP TABLE students; --")
config_manager = MagicMock() config_manager = MagicMock()
response = validate_target_table_schema(req, config_manager) response = await validate_target_table_schema(req, config_manager)
assert response.table_exists is False assert response.table_exists is False
assert response.error is not None assert response.error is not None
assert "Invalid target schema name" in response.error assert "Invalid target schema name" in response.error
assert response.all_present is False assert response.all_present is False
@patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor") @patch("src.plugins.translate.service_target_schema.SupersetSqlLabExecutor")
def test_table_not_exists(self, mock_executor, build_request) -> None: async def test_table_not_exists(self, mock_executor, build_request) -> None:
"""Таблица не существует — пустой data.""" """Таблица не существует — пустой data."""
req = build_request() req = build_request()
config_manager = MagicMock() config_manager = MagicMock()
instance = mock_executor.return_value instance = mock_executor.return_value
instance.resolve_database_id.return_value = None instance.resolve_database_id = AsyncMock(return_value=None)
instance.get_database_backend.return_value = "postgresql" instance.get_database_backend.return_value = "postgresql"
instance.get_database_name.return_value = "test_db" instance.get_database_name.return_value = "test_db"
instance.execute_and_poll.return_value = { instance.execute_and_poll = AsyncMock(return_value={
"status": "success", "status": "success",
"raw_response": { "raw_response": {
"columns": [{"name": "column_name"}], "columns": [{"name": "column_name"}],
"data": [], "data": [],
}, },
} })
response = validate_target_table_schema(req, config_manager) response = await validate_target_table_schema(req, config_manager)
assert response.table_exists is False assert response.table_exists is False
assert response.error is None assert response.error is None
assert response.all_present is False assert response.all_present is False