(pytest) fail on tests external calls

The backend tests must not try to call the real world.
This commit is contained in:
Quentin BEY
2025-04-02 16:58:31 +02:00
parent 61c3b6ac6b
commit e23d236614
3 changed files with 83 additions and 66 deletions

30
src/backend/conftest.py Normal file
View File

@@ -0,0 +1,30 @@
"""Global fixtures for the backend tests."""
import pytest
from urllib3.connectionpool import HTTPConnectionPool
@pytest.fixture(autouse=True)
def no_http_requests(monkeypatch):
"""
Prevents HTTP requests from being made during tests.
This is useful for tests that do not require actual HTTP requests
and helps to avoid network-related issues.
Credits: https://blog.jerrycodes.com/no-http-requests/
"""
allowed_hosts = {"localhost"}
original_urlopen = HTTPConnectionPool.urlopen
def urlopen_mock(self, method, url, *args, **kwargs):
if self.host in allowed_hosts:
return original_urlopen(self, method, url, *args, **kwargs)
raise RuntimeError(
f"The test was about to {method} {self.scheme}://{self.host}{url}"
)
monkeypatch.setattr(
"urllib3.connectionpool.HTTPConnectionPool.urlopen", urlopen_mock
)

View File

@@ -4,7 +4,6 @@ Test for team accesses API endpoints in People's core app : delete
import json import json
import random import random
import re
import pytest import pytest
import responses import responses
@@ -157,16 +156,18 @@ def test_api_team_accesses_delete_owners_last_owner():
assert models.TeamAccess.objects.count() == 1 assert models.TeamAccess.objects.count() == 1
@responses.activate
def test_api_team_accesses_delete_webhook(): def test_api_team_accesses_delete_webhook():
""" """
When the team has a webhook, deleting a team access should fire a call. When the team has a webhook, deleting a team access should fire a call.
""" """
user = factories.UserFactory() user = factories.UserFactory()
team = factories.TeamFactory(users=[(user, "administrator")]) team = factories.TeamFactory(users=[(user, "administrator")])
webhook = factories.TeamWebhookFactory(team=team)
access = factories.TeamAccessFactory( access = factories.TeamAccessFactory(
team=team, role=random.choice(["member", "administrator"]) team=team, role=random.choice(["member", "administrator"])
) )
# add webhook after access to prevent webhook from being triggered
webhook = factories.TeamWebhookFactory(team=team)
assert models.TeamAccess.objects.count() == 2 assert models.TeamAccess.objects.count() == 2
assert models.TeamAccess.objects.filter(user=access.user).exists() assert models.TeamAccess.objects.filter(user=access.user).exists()
@@ -174,42 +175,34 @@ def test_api_team_accesses_delete_webhook():
client = APIClient() client = APIClient()
client.force_login(user) client.force_login(user)
with responses.RequestsMock() as rsps: patch_response = responses.patch(webhook.url, status=200, json={})
# Ensure successful response by scim provider using "responses":
rsp = rsps.add(
rsps.PATCH,
re.compile(r".*/Groups/.*"),
body="{}",
status=200,
content_type="application/json",
)
response = client.delete( response = client.delete(
f"/api/v1.0/teams/{team.id!s}/accesses/{access.id!s}/", f"/api/v1.0/teams/{team.id!s}/accesses/{access.id!s}/",
) )
assert response.status_code == 204 assert response.status_code == 204
assert rsp.call_count == 1 # Check the request was made
assert rsps.calls[0].request.url == webhook.url assert patch_response.call_count == 1
# Payload sent to scim provider # Payload sent to scim provider
payload = json.loads(rsps.calls[0].request.body) scim_payload = json.loads(patch_response.calls[0].request.body)
assert payload == { assert scim_payload == {
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [ "Operations": [
{ {
"op": "remove", "op": "remove",
"path": "members", "path": "members",
"value": [ "value": [
{ {
"value": str(access.user.id), "value": str(access.user.id),
"email": access.user.email, "email": access.user.email,
"type": "User", "type": "User",
} }
], ],
} }
], ],
} }
assert models.TeamAccess.objects.count() == 1 assert models.TeamAccess.objects.count() == 1
assert models.TeamAccess.objects.filter(user=access.user).exists() is False assert models.TeamAccess.objects.filter(user=access.user).exists() is False

View File

@@ -83,47 +83,41 @@ def test_models_team_accesses_create_webhook():
} }
@responses.activate
def test_models_team_accesses_delete_webhook(): def test_models_team_accesses_delete_webhook():
""" """
When the team has a webhook, deleting a team access should fire a call. When the team has a webhook, deleting a team access should fire a call.
""" """
team = factories.TeamFactory() team = factories.TeamFactory()
webhook = factories.TeamWebhookFactory(team=team)
access = factories.TeamAccessFactory(team=team) access = factories.TeamAccessFactory(team=team)
# add webhook after access to prevent webhook from being triggered
webhook = factories.TeamWebhookFactory(team=team)
with responses.RequestsMock() as rsps: # Ensure successful response by scim provider using "responses":
# Ensure successful response by scim provider using "responses": rsp = responses.patch(webhook.url, status=200, json={})
rsp = rsps.add(
rsps.PATCH,
re.compile(r".*/Groups/.*"),
body="{}",
status=200,
content_type="application/json",
)
access.delete() access.delete()
assert rsp.call_count == 1 assert rsp.call_count == 1
assert rsps.calls[0].request.url == webhook.url
# Payload sent to scim provider # Payload sent to scim provider
payload = json.loads(rsps.calls[0].request.body) payload = json.loads(rsp.calls[0].request.body)
assert payload == { assert payload == {
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [ "Operations": [
{ {
"op": "remove", "op": "remove",
"path": "members", "path": "members",
"value": [ "value": [
{ {
"value": str(access.user.id), "value": str(access.user.id),
"email": access.user.email, "email": access.user.email,
"type": "User", "type": "User",
} }
], ],
} }
], ],
} }
assert models.TeamAccess.objects.exists() is False assert models.TeamAccess.objects.exists() is False