Skip to content

Add mock HTTP response#22677

Merged
mwdd146980 merged 4 commits into
mwdd146980/httpx-migration-basefrom
mwdd146980/add-mockhttpresponse
Feb 20, 2026
Merged

Add mock HTTP response#22677
mwdd146980 merged 4 commits into
mwdd146980/httpx-migration-basefrom
mwdd146980/add-mockhttpresponse

Conversation

@mwdd146980

@mwdd146980 mwdd146980 commented Feb 18, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds MockHTTPResponse — a library-agnostic mock HTTP response for use in integration tests — as the first concrete implementation on top of the HTTPResponseProtocol and exception hierarchy introduced in the feature branch.

MockHTTPResponse (http_testing.py)

Implements HTTPResponseProtocol without depending on requests or httpx:

  • Full response API: .json(), .text, .content, .status_code, .headers, .cookies, .elapsed, .encoding
  • Streaming: iter_content() and iter_lines() with behavior matching requests.Response
  • raise_for_status() raises HTTPStatusError for 4xx/5xx responses
  • close() is a no-op (matches requests.Response — content is already buffered in memory)
  • No external dependencies (stdlib only)

Migration (datadog_checks_base/tests/)

All three files in datadog_checks_base/tests/ that used MockResponse from datadog_checks.dev.http have been migrated to MockHTTPResponse. The migration is a minimal import swap — call sites are identical:

# Before
from datadog_checks.dev.http import MockResponse

# After
from datadog_checks.base.utils.http_testing import MockHTTPResponse
File Usages Tests
tests/base/utils/http/test_authtoken.py 2 49 pass
tests/base/utils/http/test_kerberos_unit.py 4 pass
tests/base/checks/openmetrics/test_legacy/test_openmetrics.py 24 103 pass

The openmetrics migration also validated two additional API surface requirements (encoding attribute and close() method) that were added to MockHTTPResponse in this PR.

Test coverage (test_http_testing.py)

6 tests covering the logic we own:

  • json_data auto-sets Content-Type header
  • raise_for_status() raises for 4xx and 5xx
  • iter_lines() preserves empty lines but strips trailing delimiter
  • Leading newline normalization

Motivation

RFC

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Add the qa/skip-qa label if the PR doesn't need to be tested during QA.
  • If you need to backport this PR to another branch, you can add the backport/<branch-name> label to the PR and it will automatically open a backport PR once this one is merged

@mwdd146980 mwdd146980 self-assigned this Feb 18, 2026
@mwdd146980 mwdd146980 changed the title Mwdd146980/add mockhttpresponse Add library-agnostic mock HTTP response implementation Feb 18, 2026
@mwdd146980 mwdd146980 changed the title Add library-agnostic mock HTTP response implementation Add library-agnostic mock HTTP response Feb 18, 2026
@mwdd146980 mwdd146980 changed the title Add library-agnostic mock HTTP response Add library-agnostic HTTP exception hierarchy and mock HTTP response Feb 18, 2026
@mwdd146980 mwdd146980 marked this pull request as ready for review February 18, 2026 20:18
@mwdd146980 mwdd146980 requested a review from a team as a code owner February 18, 2026 20:18

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a63b6ce889

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread datadog_checks_base/datadog_checks/base/utils/http_testing.py Outdated
Comment thread datadog_checks_base/datadog_checks/base/utils/http_testing.py Outdated
@datadog-official

datadog-official Bot commented Feb 18, 2026

Copy link
Copy Markdown
Contributor

⚠️ Tests

Fix all issues with BitsAI or with Cursor

⚠️ Warnings

🧪 1 Test failed

test_downloader from test_downloader.py (Datadog) (Fix with Cursor)
RetryError[<Future at 0x7fe85df05010 state=finished raised CalledProcessError>]

ℹ️ Info

❄️ No new flaky tests detected

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 1c3c266 | Docs | Datadog PR Page | Was this helpful? Give us feedback!

@codecov

codecov Bot commented Feb 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.96104% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.51%. Comparing base (7677da7) to head (1c3c266).

Additional details and impacted files
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

mwdd146980 added a commit that referenced this pull request Feb 18, 2026
Applied skill-based review to PR #22677 and made two improvements:

1. Fix protocol compliance: Update __exit__ signature
   - Changed from __exit__(self, *args: Any) -> None
   - To: __exit__(self, exc_type, exc_val, exc_tb) -> bool | None
   - Now correctly implements HTTPResponseProtocol specification

2. Add behavioral compatibility tests
   - Added TestMockHTTPResponseCompatibility class with 6 tests
   - Verifies MockHTTPResponse matches requests.Response behavior
   - Tests cover: iter_lines (bytes/strings/delimiters), iter_content,
     context manager, and raise_for_status

Test results: 40/40 tests passing (34 existing + 6 new)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
mwdd146980 added a commit that referenced this pull request Feb 18, 2026
Re-export HTTP exceptions and protocol types to enable library-agnostic
HTTP client usage across datadog_checks_base and datadog_checks_dev.

Changes:
- datadog_checks_base/utils/http.py: Re-export HTTP exceptions for
  single import location. Add TYPE_CHECKING imports for protocol hints.
  Add docstring to RequestsWrapper indicating HTTPClientProtocol conformance.
- datadog_checks_dev/http.py: Re-export MockHTTPResponse for protocol-based
  testing. Add __all__ to expose both MockResponse and MockHTTPResponse.

This enables:
  from datadog_checks.base.utils.http import HTTPError, HTTPTimeoutError
  from datadog_checks.dev.http import MockHTTPResponse

Part of Phase 1 httpx migration - Integration & Re-exports (Steps 4-5).
Depends on PR #22677 (exceptions + testing utilities).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
mwdd146980 added a commit that referenced this pull request Feb 18, 2026
Resolve protocol signature mismatch and getpeercert lambda issue that
were introduced during branch merges.

Changes:
- http_protocol.py: Update iter_lines signature to accept str | bytes | None
  for delimiter parameter and return Iterator[bytes | str] to match PR #22677
  and be compatible with MockHTTPResponse implementation
- http_testing.py: Replace broken lambda with proper mock_getpeercert function
  that accepts self parameter to fix 'multiple values for argument' error

These changes align PR #22680 with the working versions from PR #22677.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
mwdd146980 added a commit that referenced this pull request Feb 19, 2026
Re-export HTTP exceptions and protocol types to enable library-agnostic
HTTP client usage across datadog_checks_base and datadog_checks_dev.

Changes:
- datadog_checks_base/utils/http.py: Re-export HTTP exceptions for
  single import location. Add TYPE_CHECKING imports for protocol hints.
  Add docstring to RequestsWrapper indicating HTTPClientProtocol conformance.
- datadog_checks_dev/http.py: Re-export MockHTTPResponse for protocol-based
  testing. Add __all__ to expose both MockResponse and MockHTTPResponse.

This enables:
  from datadog_checks.base.utils.http import HTTPError, HTTPTimeoutError
  from datadog_checks.dev.http import MockHTTPResponse

Part of Phase 1 httpx migration - Integration & Re-exports (Steps 4-5).
Depends on PR #22677 (exceptions + testing utilities).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
mwdd146980 added a commit that referenced this pull request Feb 19, 2026
Resolve protocol signature mismatch and getpeercert lambda issue that
were introduced during branch merges.

Changes:
- http_protocol.py: Update iter_lines signature to accept str | bytes | None
  for delimiter parameter and return Iterator[bytes | str] to match PR #22677
  and be compatible with MockHTTPResponse implementation
- http_testing.py: Replace broken lambda with proper mock_getpeercert function
  that accepts self parameter to fix 'multiple values for argument' error

These changes align PR #22680 with the working versions from PR #22677.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@mwdd146980 mwdd146980 force-pushed the mwdd146980/add-mockhttpresponse branch from f0e141d to af33176 Compare February 19, 2026 22:35
@mwdd146980 mwdd146980 changed the title Add library-agnostic HTTP exception hierarchy and mock HTTP response Add mock HTTP response Feb 19, 2026
mwdd146980 and others added 4 commits February 20, 2026 11:12
MockHTTPResponse implements HTTPResponseProtocol without depending on
requests or httpx. It supports the full response API (.json(), .text,
.content, .status_code, .headers, .cookies, .elapsed), streaming via
iter_content() and iter_lines(), raise_for_status() using HTTPStatusError,
and context manager usage.

Demonstrates usage by migrating test_authtoken.py from MockResponse to
MockHTTPResponse — a drop-in replacement with protocol compliance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s_unit.py

Also adds three missing API surface members discovered during migration:
- encoding attribute (accessed by openmetrics mixin before iter_lines)
- close() no-op (called by openmetrics mixin after response processing)
- Removes _stream_consumed guard so the same instance can be reused
  across repeated mock.MagicMock(return_value=...) calls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two correctness fixes in MockHTTPResponse:

1. When json_data and headers are both provided, the caller's headers dict
   was mutated in-place via setdefault(). Now copies before modifying.

2. self.headers was a plain dict (case-sensitive). HTTP headers are
   case-insensitive per RFC 7230 §3.2. Replace with _CaseInsensitiveDict
   that stores keys lowercased, matching requests.Response behaviour.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mwdd146980 mwdd146980 force-pushed the mwdd146980/add-mockhttpresponse branch from e409df5 to 1c3c266 Compare February 20, 2026 16:27
@mwdd146980 mwdd146980 merged commit beb72ad into mwdd146980/httpx-migration-base Feb 20, 2026
298 of 301 checks passed
@mwdd146980 mwdd146980 deleted the mwdd146980/add-mockhttpresponse branch February 20, 2026 18:13
mwdd146980 added a commit that referenced this pull request Feb 20, 2026
* Add MockHTTPResponse for library-agnostic HTTP response mocking

MockHTTPResponse implements HTTPResponseProtocol without depending on
requests or httpx. It supports the full response API (.json(), .text,
.content, .status_code, .headers, .cookies, .elapsed), streaming via
iter_content() and iter_lines(), raise_for_status() using HTTPStatusError,
and context manager usage.

Demonstrates usage by migrating test_authtoken.py from MockResponse to
MockHTTPResponse — a drop-in replacement with protocol compliance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Expand MockHTTPResponse usage to test_openmetrics.py and test_kerberos_unit.py

Also adds three missing API surface members discovered during migration:
- encoding attribute (accessed by openmetrics mixin before iter_lines)
- close() no-op (called by openmetrics mixin after response processing)
- Removes _stream_consumed guard so the same instance can be reused
  across repeated mock.MagicMock(return_value=...) calls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Reformat with ddev test --fmt

* Fix headers mutation and add case-insensitive header dict

Two correctness fixes in MockHTTPResponse:

1. When json_data and headers are both provided, the caller's headers dict
   was mutated in-place via setdefault(). Now copies before modifying.

2. self.headers was a plain dict (case-sensitive). HTTP headers are
   case-insensitive per RFC 7230 §3.2. Replace with _CaseInsensitiveDict
   that stores keys lowercased, matching requests.Response behaviour.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
mwdd146980 added a commit that referenced this pull request Mar 19, 2026
* Add MockHTTPResponse for library-agnostic HTTP response mocking

MockHTTPResponse implements HTTPResponseProtocol without depending on
requests or httpx. It supports the full response API (.json(), .text,
.content, .status_code, .headers, .cookies, .elapsed), streaming via
iter_content() and iter_lines(), raise_for_status() using HTTPStatusError,
and context manager usage.

Demonstrates usage by migrating test_authtoken.py from MockResponse to
MockHTTPResponse — a drop-in replacement with protocol compliance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Expand MockHTTPResponse usage to test_openmetrics.py and test_kerberos_unit.py

Also adds three missing API surface members discovered during migration:
- encoding attribute (accessed by openmetrics mixin before iter_lines)
- close() no-op (called by openmetrics mixin after response processing)
- Removes _stream_consumed guard so the same instance can be reused
  across repeated mock.MagicMock(return_value=...) calls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Reformat with ddev test --fmt

* Fix headers mutation and add case-insensitive header dict

Two correctness fixes in MockHTTPResponse:

1. When json_data and headers are both provided, the caller's headers dict
   was mutated in-place via setdefault(). Now copies before modifying.

2. self.headers was a plain dict (case-sensitive). HTTP headers are
   case-insensitive per RFC 7230 §3.2. Replace with _CaseInsensitiveDict
   that stores keys lowercased, matching requests.Response behaviour.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant