Skip to content
Open
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ ENHANCEMENTS:
* Updated the version of `super-linter` used in the `build_validation_develop` workflow ([#4957](https://github.com/microsoft/AzureTRE/issues/4957))

BUG FIXES:
* Fix Health check can falsely return OK even if Cosmos is down or inaccessible. ([#4926](https://github.com/microsoft/AzureTRE/issues/4926))
* Fix UI TypeScript deprecation warning by updating `moduleResolution` to `bundler` in `tsconfig.json`. ([#4968](https://github.com/microsoft/AzureTRE/issues/4968))
* Fix API timeout and name collision failures on workspace creation by checking storage account name availability and improved logging. ([#4946](https://github.com/microsoft/AzureTRE/pull/4946))
* Fix error handling in airlock processor ([#4929](https://github.com/microsoft/AzureTRE/pull/4929))
Expand Down
2 changes: 1 addition & 1 deletion api_app/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.25.29"
__version__ = "0.25.30"
3 changes: 2 additions & 1 deletion api_app/services/health_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ async def create_state_store_status() -> Tuple[StatusEnum, str]:
message = ""
try:
container: ContainerProxy = await Database().get_container_proxy(STATE_STORE_RESOURCES_CONTAINER)
container.query_items("SELECT TOP 1 * FROM c")
async for _ in container.query_items("SELECT TOP 1 VALUE 1 FROM c", max_item_count=1):
break
except exceptions.ServiceRequestError:
status = StatusEnum.not_ok
message = strings.STATE_STORE_ENDPOINT_NOT_RESPONDING
Expand Down
55 changes: 53 additions & 2 deletions api_app/tests_ma/test_services/test_health_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from unittest.mock import AsyncMock, MagicMock
import pytest
from azure.core.exceptions import ServiceRequestError
from azure.cosmos.exceptions import CosmosHttpResponseError
from azure.servicebus.exceptions import ServiceBusConnectionError
from mock import patch
Comment thread
JC-wk marked this conversation as resolved.
from models.schemas.status import StatusEnum
Expand All @@ -11,12 +12,40 @@
pytestmark = pytest.mark.asyncio


@patch("azure.cosmos.aio.ContainerProxy.query_items", return_value=AsyncMock())
async def test_get_state_store_status_responding(_) -> None:
def create_mock_container(query_results=None, query_error=None):
container_mock = MagicMock()

# Mock query_items()
query_items_mock = MagicMock()
if query_error:
query_items_mock.return_value.__aiter__.side_effect = query_error
else:
query_items_mock.return_value.__aiter__.return_value = query_results or []

container_mock.query_items = query_items_mock
return container_mock


@patch("api.dependencies.database.Database.get_container_proxy")
async def test_get_state_store_status_responding(get_container_proxy_mock) -> None:
container_mock = create_mock_container(query_results=[{"id": "item"}])
get_container_proxy_mock.return_value = container_mock
status, message = await health_checker.create_state_store_status()

assert status == StatusEnum.ok
assert message == ""
container_mock.query_items.assert_called_once_with("SELECT TOP 1 VALUE 1 FROM c", max_item_count=1)


@patch("api.dependencies.database.Database.get_container_proxy")
async def test_get_state_store_status_empty_results(get_container_proxy_mock) -> None:
container_mock = create_mock_container(query_results=[])
get_container_proxy_mock.return_value = container_mock
status, message = await health_checker.create_state_store_status()

assert status == StatusEnum.ok
assert message == ""
container_mock.query_items.assert_called_once_with("SELECT TOP 1 VALUE 1 FROM c", max_item_count=1)


@patch("api.dependencies.database.Database.get_container_proxy")
Expand All @@ -39,6 +68,28 @@ async def test_get_state_store_status_other_exception(container_proxy_mock) -> N
assert message == strings.UNSPECIFIED_ERROR


@patch("api.dependencies.database.Database.get_container_proxy")
async def test_get_state_store_status_cosmos_http_error(get_container_proxy_mock) -> None:
container_mock = create_mock_container(query_error=CosmosHttpResponseError(message="some message"))
get_container_proxy_mock.return_value = container_mock
status, message = await health_checker.create_state_store_status()

assert status == StatusEnum.not_ok
assert message == strings.STATE_STORE_ENDPOINT_NOT_ACCESSIBLE
container_mock.query_items.assert_called_once_with("SELECT TOP 1 VALUE 1 FROM c", max_item_count=1)


@patch("api.dependencies.database.Database.get_container_proxy")
async def test_get_state_store_status_service_request_error(get_container_proxy_mock) -> None:
container_mock = create_mock_container(query_error=ServiceRequestError(message="some message"))
get_container_proxy_mock.return_value = container_mock
status, message = await health_checker.create_state_store_status()

assert status == StatusEnum.not_ok
assert message == strings.STATE_STORE_ENDPOINT_NOT_RESPONDING
container_mock.query_items.assert_called_once_with("SELECT TOP 1 VALUE 1 FROM c", max_item_count=1)


@patch("core.credentials.get_credential_async_context")
@patch("services.health_checker.ServiceBusClient")
async def test_get_service_bus_status_responding(service_bus_client_mock, get_credential_async_context) -> None:
Expand Down
Loading