Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
63074a3
fix: set asyncio_default_fixture_loop_scope to avoid pytest warning
CodeVishal-17 Jan 5, 2026
e8e21a6
Fix pytest-asyncio v1.x async fixture usage
CodeVishal-17 Jan 7, 2026
2ef08bf
Fix pytest-asyncio deprecation by enforcing strict mode and sync fixt…
CodeVishal-17 Jan 7, 2026
02589d9
Merge branch 'main' into fix/pytest-asyncio-deprecation
CodeVishal-17 Jan 9, 2026
e4d68f7
Remove remaining pytest_asyncio fixtures and use sync pytest fixtures
CodeVishal-17 Jan 12, 2026
9ed9356
Fix remaining fixtures for pytest-asyncio strict mode
CodeVishal-17 Jan 12, 2026
f8a3815
Merge branch 'main' into fix/pytest-asyncio-deprecation
CodeVishal-17 Jan 12, 2026
435a77f
Add Bandit security scanning to PR validation workflow
CodeVishal-17 Jan 13, 2026
cc2c3e6
Remove Bandit config and CI steps from pytest-asyncio fix PR
CodeVishal-17 Jan 14, 2026
85500c9
Fix AsyncClient fixture lifecycle for pytest-asyncio strict mode
CodeVishal-17 Jan 14, 2026
e6164c6
Resolve merge conflict in conftest.py
CodeVishal-17 Jan 14, 2026
8b1de07
Merge branch 'main' into fix/pytest-asyncio-deprecation
CodeVishal-17 Jan 14, 2026
0d21f8c
Mark airlock route tests as asyncio
CodeVishal-17 Jan 14, 2026
90fcea4
Merge branch 'fix/pytest-asyncio-deprecation' of https://github.com/C…
CodeVishal-17 Jan 14, 2026
4bbf729
Remove unrelated CI Python setup from pytest-asyncio fix
CodeVishal-17 Jan 19, 2026
61b6e12
Merge branch 'main' into fix/pytest-asyncio-deprecation
CodeVishal-17 Jan 23, 2026
59b44ca
Merge branch 'main' into fix/pytest-asyncio-deprecation
CodeVishal-17 Feb 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build_validation_develop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ jobs:
TYPESCRIPT_ES_CONFIG_FILE: ../../ui/app/eslint.config.js
TSX_CONFIG_FILE: ../../ui/app/eslint.config.js


- name: Docs validation
if: ${{ steps.filter.outputs.docs == 'true' }}
run: |
Expand Down
2 changes: 2 additions & 0 deletions api_app/pytest.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[pytest]
filterwarnings =
error
asyncio_mode = strict
asyncio_default_fixture_loop_scope = function
6 changes: 3 additions & 3 deletions api_app/tests_ma/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pytest
import pytest_asyncio

from mock import AsyncMock, patch
from azure.cosmos.aio import CosmosClient, DatabaseProxy

Expand Down Expand Up @@ -575,8 +575,8 @@ def simple_pipeline_step() -> PipelineStep:
)


@pytest_asyncio.fixture(autouse=True)
async def no_database():
@pytest.fixture(autouse=True)
def no_database():
with patch('api.dependencies.database.get_credential_async', return_value=AsyncMock()), \
patch('api.dependencies.database.CosmosClient', return_value=AsyncMock(spec=CosmosClient)) as cosmos_client_mock:
cosmos_client_mock.return_value.get_database_client.return_value = AsyncMock(spec=DatabaseProxy)
Expand Down
10 changes: 7 additions & 3 deletions api_app/tests_ma/test_api/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import pytest
import pytest_asyncio


from mock import patch

from fastapi import FastAPI
Expand Down Expand Up @@ -126,16 +128,18 @@ def inner():
return inner


@pytest_asyncio.fixture(scope='module')
@pytest.fixture(scope='module')
def app() -> FastAPI:
from main import get_application

the_app = get_application()
return the_app

return get_application()


@pytest_asyncio.fixture
async def client(app: FastAPI) -> AsyncClient:

async with AsyncClient(transport=ASGITransport(app=app), base_url="http://testserver", headers={"Content-Type": "application/json"}) as client:
yield client


50 changes: 36 additions & 14 deletions api_app/tests_ma/test_api/test_routes/test_airlock.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import time
import pytest
import pytest_asyncio

pytestmark = pytest.mark.asyncio

from mock import patch
from fastapi import status
from azure.core.exceptions import HttpResponseError
Expand All @@ -17,7 +19,6 @@
from models.domain.operation import Operation
from resources import strings
from services.authentication import get_current_workspace_owner_or_researcher_user, get_current_workspace_owner_or_researcher_user_or_airlock_manager, get_current_airlock_manager_user
pytestmark = pytest.mark.asyncio


WORKSPACE_ID = "abc000d3-82da-4bfc-b6e9-9a7853ef753e"
Expand Down Expand Up @@ -127,18 +128,31 @@ def inner():


class TestAirlockRoutesThatRequireOwnerOrResearcherRights():
@pytest_asyncio.fixture(autouse=True, scope='class')
@pytest.fixture(autouse=True, scope="class")
def log_in_with_researcher_user(self, app, researcher_user):
app.dependency_overrides[get_current_workspace_owner_or_researcher_user] = researcher_user
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_airlock_manager] = researcher_user
with patch("api.routes.airlock.AirlockRequestRepository.create_airlock_request_item", return_value=sample_airlock_request_object()), \
patch("api.routes.workspaces.OperationRepository.resource_has_deployed_operation"), \
patch("api.routes.airlock.AirlockRequestRepository.save_item"), \
patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id"), \
patch("services.aad_authentication.AzureADAuthorization.get_workspace_user_emails_by_role_assignment", return_value={"WorkspaceResearcher": ["researcher@outlook.com"], "WorkspaceOwner": ["owner@outlook.com"], "AirlockManager": ["manager@outlook.com"]}):
with patch(
"api.routes.airlock.AirlockRequestRepository.create_airlock_request_item",
return_value=sample_airlock_request_object(),
), patch(
"api.routes.workspaces.OperationRepository.resource_has_deployed_operation"
), patch(
"api.routes.airlock.AirlockRequestRepository.save_item"
), patch(
"api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id"
), patch(
"services.aad_authentication.AzureADAuthorization.get_workspace_user_emails_by_role_assignment",
return_value={
"WorkspaceResearcher": ["researcher@outlook.com"],
"WorkspaceOwner": ["owner@outlook.com"],
"AirlockManager": ["manager@outlook.com"],
},
):
yield
app.dependency_overrides = {}


# [GET] /workspaces/{workspace_id}/requests}
@patch("api.routes.airlock.AirlockRequestRepository.get_airlock_requests", return_value=[])
async def test_get_all_airlock_requests_by_workspace_returns_200(self, _, app, client):
Expand Down Expand Up @@ -303,17 +317,24 @@ async def test_get_airlock_container_link_returned_as_expected(self, get_airlock


class TestAirlockRoutesThatRequireAirlockManagerRights():
@pytest_asyncio.fixture(autouse=True, scope='class')
@pytest.fixture(autouse=True, scope="class")
def log_in_with_airlock_manager_user(self, app, airlock_manager_user):
app.dependency_overrides[get_current_airlock_manager_user] = airlock_manager_user
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_airlock_manager] = airlock_manager_user
with patch("services.airlock.AirlockRequestRepository.create_airlock_request_item", return_value=sample_airlock_request_object()), \
patch("api.routes.workspaces.OperationRepository.resource_has_deployed_operation"), \
patch("services.airlock.AirlockRequestRepository.save_item"), \
patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id"):
with patch(
"services.airlock.AirlockRequestRepository.create_airlock_request_item",
return_value=sample_airlock_request_object(),
), patch(
"api.routes.workspaces.OperationRepository.resource_has_deployed_operation"
), patch(
"services.airlock.AirlockRequestRepository.save_item"
), patch(
"api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id"
):
yield
app.dependency_overrides = {}


# [POST] /workspaces/{workspace_id}/requests/{airlock_request_id}/review
@patch("services.airlock.AirlockRequestRepository.read_item_by_id", return_value=sample_airlock_request_object(status=AirlockRequestStatus.InReview))
@patch("services.airlock.AirlockRequestRepository.create_airlock_review_item", return_value=sample_airlock_review_object())
Expand Down Expand Up @@ -463,14 +484,15 @@ async def test_post_revoke_airlock_request_missing_reason_returns_422(self, _, a

class TestAirlockRoutesPermissions():

@pytest_asyncio.fixture()
@pytest.fixture()
def log_in_with_user(self, app):
def inner(user):
app.dependency_overrides[get_current_workspace_owner_or_researcher_user] = user
app.dependency_overrides[get_current_airlock_manager_user] = user
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_airlock_manager] = user
return inner


@pytest.mark.parametrize("role", (role for role in get_required_roles(endpoint=create_draft_request)))
@patch("api.routes.workspaces.OperationRepository.resource_has_deployed_operation")
@patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id", return_value=sample_workspace(WORKSPACE_ID))
Expand Down