Skip to content

integration: Flask blueprint before_request causes AttributeError in test routing #320

@nycomp

Description

@nycomp

Problem

During integration testing, Flask's before_request handlers throw AttributeError exceptions when the test routing infrastructure (TestCampusRequest, flask_test.register_test_app) is used. The error occurs because the request object lacks certain attributes expected by the before_request handlers.

Root Cause

The TestCampusRequest class (in tests/flask_test.py) patches campus_python to use Flask's test client for HTTP requests. However:

  1. Flask test client requests are minimal Request objects
  2. campus.auth.routes.__init__.py has a before_request handler that calls authenticate()
  3. The authenticate() function expects headers and other attributes that may not be present in test requests

Error Trace

WARNING:campus.common.webauth.http:Missing Authorization header. Header keys: ['User-Agent', 'Host']
ERROR:campus.common.errors:APIError in ...campus\common\webauth\http\__init__.py: Missing Authorization header.
Traceback (most recent call last):
  File "...\flask\app.py", line 915, in full_dispatch_request
  File "...\flask\app.py", line 1291, in preprocess_request
  File "...\campus\auth\routes\__init__.py", line 49, in authenticate
    ...
campus.common.errors.api_errors.UnauthorizedError: Missing Authorization header.

Code Context

campus/auth/routes/__init__.py - the before_request handler:

@app.before_request
def authenticate():
    req_header = req.headers.get("Authorization")
    if not req_header:
        raise api_errors.UnauthorizedError(
            message="Missing Authorization header"
        )

Why This Fails in Tests

  1. Integration tests intentionally test unauthorized endpoints
  2. The before_request handler runs BEFORE the test can make assertions about the response
  3. The errors are logged but tests still pass (exception is caught and handled)
  4. This creates confusing test output with WARNING/ERROR logs for passing tests

Potential Solutions

  1. Add test mode detection to before_request: Skip authentication in test mode

    @app.before_request
    def authenticate():
        if os.getenv("ENV") == "testing":
            return  # Skip auth in tests
        # ... rest of auth logic
  2. Configure test apps differently: Use app.testing = True to disable certain error handlers

  3. Mock authentication in tests: Set up proper auth headers in test requests

  4. Add custom error handler in test mode: Suppress UnauthorizedError in test fixtures

  5. Conditional before_request registration: Don't register the before_request handler in test mode

Trade-offs

Solution Pros Cons
Test mode check in before_request Simple, centralized Auth code needs test awareness
Conditional registration Cleaner separation of concerns More complex app setup
Mock in tests No production changes More test setup code

Test Case

def test_unauthorized_endpoint_does_not_log_errors():
    """Verify that unauthorized requests don't spam logs in test mode."""
    with auth_app.test_client() as client:
        # This should return 401, but not log WARNING/ERROR
        response = client.get("/auth/v1/vault")
        assert response.status_code == 401
        
        # No WARNING/ERROR should be logged for expected 401s
        # (Currently logs WARNING + ERROR stack trace)

Priority

Low - Tests pass and the errors are logged, not raised. The main issue is confusing test output and potential masking of real errors.

Labels

bug, integration-tests, flask, test-infrastructure, good-first-issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions