Skip to content

Conversation

@jonathangreen
Copy link
Member

@jonathangreen jonathangreen commented Jan 7, 2026

Description

Fix a bug where the OPDS2+ODL integration could not fulfill content with the streaming DRM type. The streaming DRM handler was missing from the fulfillment logic, causing these requests to fail.

The fix adds a new handler for STREAMING_DRM that:

  • Maps the streaming content type (e.g., Streaming Text) to the appropriate link media type (text/html)
  • Looks up the publication link with the correct type
  • Returns a RedirectFulfillment to send the patron to the streaming reader

Also adds proper error handling when an unsupported streaming content type is encountered.

Motivation and Context

This resolves PP-3467 and should unblock PP-3296.

Streaming content from OPDS2+ODL providers could not be fulfilled because the _license_fulfill method did not have a handler for the STREAMING_DRM scheme. This caused the code to fall through to the default DRM handler, which looks for a license rel link with the DRM scheme as the type—incorrect for streaming content.

How Has This Been Tested?

  • Added a new parameterized test case for streaming DRM fulfillment in test_fulfill_success
  • Added a dedicated test test_fulfill_streaming_unsupported_content_type to verify error handling when an unsupported content type is used with streaming DRM
  • Did some manual testing locally

Checklist

  • I have updated the documentation accordingly.
  • All new and existing tests passed.

@jonathangreen jonathangreen added the bug Something isn't working label Jan 7, 2026
def _license_fulfill(
self, loan: Loan, delivery_mechanism: LicensePoolDeliveryMechanism
) -> Fulfillment:
# We are unable to fulfill a loan that doesn't have its external identifier set,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change isn't related, but while I was here, I noticed the first line of the doc comment was duplicated.

@jonathangreen jonathangreen requested a review from a team January 7, 2026 16:39
…ming DRM type

- Add test coverage for streaming DRM in test_fulfill_success
- Add test for unsupported streaming content type error case
- Add helpful error messages when streaming content type is unsupported
- Refactor test to use content_type parameter for cleaner parametrization
@jonathangreen jonathangreen force-pushed the bugfix/opds-odl-streaming-fulfill branch from 3717f1b to f066a81 Compare January 7, 2026 16:41
Copy link
Contributor

@tdilauro tdilauro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me! 🛠️

@codecov
Copy link

codecov bot commented Jan 7, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.78%. Comparing base (afdef20) to head (f066a81).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2956   +/-   ##
=======================================
  Coverage   92.78%   92.78%           
=======================================
  Files         454      454           
  Lines       42844    42852    +8     
  Branches     5976     5978    +2     
=======================================
+ Hits        39752    39760    +8     
  Misses       2021     2021           
  Partials     1071     1071           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jonathangreen jonathangreen merged commit 20896c5 into main Jan 7, 2026
26 of 27 checks passed
@jonathangreen jonathangreen deleted the bugfix/opds-odl-streaming-fulfill branch January 7, 2026 17:40
jonathangreen added a commit that referenced this pull request Jan 8, 2026
…) (#2966)

## Description

This refactoring removes the streaming-specific conditional from
`LoanController.fulfill()` by creating a new `StreamingFulfillment`
class that encapsulates OPDS feed response generation.

It shouldn't change the feed output, but in working on
#2965,
#2962,
#2956 it became
clear this refactoring would help the maintainability of this code.

Changes:
- Add `StreamingFulfillment` class that generates OPDS feed entries
containing the streaming fulfillment link
- Automatically append `STREAMING_PROFILE` to content type in
constructor
- Update `Fulfillment.response()` signature to accept optional
`circulation` and `loan` parameters for subclasses that need them
- Update `LoanController` to pass context to `fulfillment.response()`
instead of special-casing streaming mechanisms
- Update ODL and Overdrive integrations to return `StreamingFulfillment`
for streaming delivery mechanisms
- Add comprehensive tests for the new fulfillment class
- Update existing tests to use `StreamingFulfillment` where appropriate

## Motivation and Context

Previously, the `LoanController.fulfill()` method had special-case logic
to check if a delivery mechanism was streaming and generate an OPDS feed
response.

This refactoring allows integrations to explicitly choose their response
format by returning the appropriate fulfillment type, rather than having
the controller make that decision based on delivery mechanism
properties.

## How Has This Been Tested?

- Added comprehensive unit tests for `StreamingFulfillment` class
- Updated existing integration tests to use `StreamingFulfillment`
- All existing tests pass

## Checklist

- [x] I have updated the documentation accordingly.
- [x] All new and existing tests passed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants