Python SDK for shellbound Django applications. Provides ShellApp, ShardContext, ShellboundMiddleware. Emits Chronicle events to stdout in dev mode. Includes fix for IndexError in apps.py when DJANGO_SETTINGS_MODULE has no dots (e.g. instance_settings). Shard name now falls back safely without eager default argument parsing. Implements SHELLBOUND-APP-0001 §4 (dev mode). Wired into entropyopposition as of 2026-03-18.
94 lines
2.9 KiB
Python
94 lines
2.9 KiB
Python
"""Tests for Django middleware. Requires Django."""
|
|
|
|
import json
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
try:
|
|
from substrate_sdk.django.middleware import ShellboundMiddleware, _extract_did, set_emitter
|
|
HAS_DJANGO = True
|
|
except ImportError:
|
|
HAS_DJANGO = False
|
|
|
|
pytestmark = pytest.mark.skipif(not HAS_DJANGO, reason="Django not installed")
|
|
|
|
|
|
class TestShellboundMiddleware:
|
|
|
|
def test_emits_request_event(self, capsys):
|
|
emitter = MagicMock()
|
|
set_emitter(emitter)
|
|
|
|
request = MagicMock()
|
|
request.method = "GET"
|
|
request.path = "/api/test/"
|
|
request.resolver_match = MagicMock(view_name="test-view")
|
|
request.auth = None
|
|
request.user = MagicMock(is_authenticated=False)
|
|
|
|
response = MagicMock(status_code=200)
|
|
get_response = MagicMock(return_value=response)
|
|
mw = ShellboundMiddleware(get_response)
|
|
result = mw(request)
|
|
|
|
emitter.request.assert_called_once()
|
|
call_kwargs = emitter.request.call_args
|
|
assert call_kwargs.kwargs["method"] == "GET"
|
|
assert call_kwargs.kwargs["status"] == 200
|
|
|
|
def test_captures_status_code(self):
|
|
emitter = MagicMock()
|
|
set_emitter(emitter)
|
|
|
|
request = MagicMock(method="POST", path="/api/create/", auth=None)
|
|
request.user = MagicMock(is_authenticated=False)
|
|
request.resolver_match = MagicMock(view_name="create")
|
|
|
|
response = MagicMock(status_code=201)
|
|
mw = ShellboundMiddleware(MagicMock(return_value=response))
|
|
mw(request)
|
|
|
|
assert emitter.request.call_args.kwargs["status"] == 201
|
|
|
|
def test_non_fatal_when_emitter_none(self):
|
|
set_emitter(None)
|
|
|
|
request = MagicMock(method="GET", path="/")
|
|
response = MagicMock(status_code=200)
|
|
mw = ShellboundMiddleware(MagicMock(return_value=response))
|
|
result = mw(request)
|
|
assert result.status_code == 200
|
|
|
|
def test_extract_did_from_user(self):
|
|
request = MagicMock()
|
|
request.auth = None
|
|
user = MagicMock()
|
|
user.is_authenticated = True
|
|
user.external_id = "entra-oid-123"
|
|
user.organization = MagicMock(slug="acme")
|
|
request.user = user
|
|
|
|
did = _extract_did(request)
|
|
assert "entra-oid-123" in did
|
|
assert "acme" in did
|
|
|
|
def test_extract_did_anonymous(self):
|
|
request = MagicMock()
|
|
request.auth = None
|
|
request.user = MagicMock(is_authenticated=False)
|
|
|
|
assert _extract_did(request) == ""
|
|
|
|
def test_duration_ms_positive(self):
|
|
emitter = MagicMock()
|
|
set_emitter(emitter)
|
|
|
|
request = MagicMock(method="GET", path="/", auth=None)
|
|
request.user = MagicMock(is_authenticated=False)
|
|
request.resolver_match = MagicMock(view_name="root")
|
|
|
|
mw = ShellboundMiddleware(MagicMock(return_value=MagicMock(status_code=200)))
|
|
mw(request)
|
|
|
|
assert emitter.request.call_args.kwargs["duration_ms"] >= 0
|