Skip to content

Conversation

@robcsegal
Copy link
Contributor

@robcsegal robcsegal commented Jan 11, 2026

Added e2e tests for billing overrides

https://softwareone.atlassian.net/browse/MPT-14926

Closes MPT-14926

  • Add e2e test config entry billing.override.id = "BOV-7202-7714" in e2e_config.test.json
  • Add pytest fixtures in tests/e2e/billing/override/conftest.py:
    • billing_override_id(e2e_config) (reads billing.override.id)
    • invalid_billing_override_id() returns "BOV-0000-0000"
  • Add async e2e tests tests/e2e/billing/override/test_async_override.py:
    • test get by id, list (fetch_page), not-found (404) and filter (id + externalId) with select & iteration
    • marked flaky
  • Add sync e2e tests tests/e2e/billing/override/test_sync_override.py:
    • test get by id, list (fetch_page), not-found (404) and filter (id + externalId) with select & iteration
    • marked flaky
  • Tests cover pagination, filtering by id and externalId, field selection, iteration, and error handling

@robcsegal robcsegal requested a review from a team as a code owner January 11, 2026 01:55
@robcsegal robcsegal requested review from d3rky and svazquezco January 11, 2026 01:55
@coderabbitai
Copy link

coderabbitai bot commented Jan 11, 2026

📝 Walkthrough

Walkthrough

Adds a billing override identifier to test configuration and introduces fixtures plus parallel synchronous and asynchronous end-to-end tests for billing override operations (get, list, not-found, filtering, field selection, pagination). Tests are marked flaky.

Changes

Cohort / File(s) Summary
Configuration
e2e_config.test.json
Added billing.override.id with value BOV-7202-7714.
Test Fixtures
tests/e2e/billing/override/conftest.py
New pytest fixtures: billing_override_id(e2e_config) (reads config value) and invalid_billing_override_id() (returns invalid ID).
E2E Test Modules
tests/e2e/billing/override/test_sync_override.py, tests/e2e/billing/override/test_async_override.py
New sync and async test suites covering: get by ID, list/pagination, 404 not-found behavior, filtering by id/externalId, field selection and iteration. Tests marked flaky.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Jira Issue Key In Title ✅ Passed The PR title contains exactly one properly formatted Jira issue key MPT-14926 at the beginning within square brackets.
Test Coverage Required ✅ Passed The PR includes test files in the tests/ folder (conftest.py with fixtures and two test modules: test_async_override.py and test_sync_override.py) and does not modify any non-test code files outside the tests/ folder.
Single Commit Required ✅ Passed The PR contains exactly one commit that appropriately bundles all related changes for adding end-to-end tests for billing overrides.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


📜 Recent review details

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02f32fc and 1ec8ae9.

📒 Files selected for processing (4)
  • e2e_config.test.json
  • tests/e2e/billing/override/conftest.py
  • tests/e2e/billing/override/test_async_override.py
  • tests/e2e/billing/override/test_sync_override.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/e2e/billing/override/conftest.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*

⚙️ CodeRabbit configuration file

**/*: For each subsequent commit in this PR, explicitly verify if previous review comments have been resolved

Files:

  • tests/e2e/billing/override/test_async_override.py
  • tests/e2e/billing/override/test_sync_override.py
  • e2e_config.test.json
**/*.py

⚙️ CodeRabbit configuration file

**/*.py: Follow the linting rules defined in pyproject.toml under [tool.ruff] and [tool.flake8] sections.
For formatting, use Ruff instead of Black. Do not suggest Black formatting changes.

Files:

  • tests/e2e/billing/override/test_async_override.py
  • tests/e2e/billing/override/test_sync_override.py
🧠 Learnings (4)
📓 Common learnings
Learnt from: albertsola
Repo: softwareone-platform/mpt-api-python-client PR: 183
File: tests/e2e/catalog/price_lists/conftest.py:29-30
Timestamp: 2026-01-08T08:34:13.551Z
Learning: In the mpt-api-python-client E2E tests, the team intentionally reuses existing API resources (via e2e_config) for read-only operations and safe mutations (e.g., updating the "notes" field) to improve test execution speed. Only destructive/dangerous tests use isolated fixtures (created_price_list or async_created_price_list) that are created and cleaned up per test.
Learnt from: robcsegal
Repo: softwareone-platform/mpt-api-python-client PR: 186
File: tests/e2e/billing/ledger/charge/test_sync_ledger_charge.py:33-39
Timestamp: 2026-01-08T23:38:26.691Z
Learning: In the mpt-api-python-client e2e tests, hardcoded values like "INV12345" for invoice external IDs are intentional and guaranteed to exist because they come from import files used to seed the test data.
📚 Learning: 2026-01-08T08:34:05.465Z
Learnt from: albertsola
Repo: softwareone-platform/mpt-api-python-client PR: 183
File: tests/e2e/catalog/price_lists/conftest.py:29-30
Timestamp: 2026-01-08T08:34:05.465Z
Learning: In end-to-end tests (e.g., tests/e2e/...), reuse existing API resources for read-only operations and safe mutations to speed up test execution. Reserve isolated fixtures (e.g., created_price_list) for destructive tests that require per-test creation and cleanup. Ensure tests document when a fixture creates/destroys data and clearly indicate which operations are destructive, so tests stay fast and properly isolated.

Applied to files:

  • tests/e2e/billing/override/test_async_override.py
  • tests/e2e/billing/override/test_sync_override.py
📚 Learning: 2026-01-08T23:38:19.565Z
Learnt from: robcsegal
Repo: softwareone-platform/mpt-api-python-client PR: 186
File: tests/e2e/billing/ledger/charge/test_sync_ledger_charge.py:33-39
Timestamp: 2026-01-08T23:38:19.565Z
Learning: In Python e2e tests under tests/e2e, hardcoded external IDs (e.g., INV12345) are intentional because they come from seeded test data. Ensure the test data seeds consistently include these IDs; if seeds change, update tests accordingly. Prefer using a named constant for such IDs (e.g., INV_EXTERNAL_ID) and document the dependency on seed data to avoid brittle tests.

Applied to files:

  • tests/e2e/billing/override/test_async_override.py
  • tests/e2e/billing/override/test_sync_override.py
📚 Learning: 2025-12-12T15:02:20.732Z
Learnt from: robcsegal
Repo: softwareone-platform/mpt-api-python-client PR: 160
File: tests/e2e/commerce/agreement/attachment/test_async_agreement_attachment.py:55-58
Timestamp: 2025-12-12T15:02:20.732Z
Learning: In pytest with pytest-asyncio, if a test function uses async fixtures but contains no await, declare the test function as def (synchronous) instead of async def. Pytest-asyncio will resolve the async fixtures automatically; this avoids linter complaints about unnecessary async functions. This pattern applies to any test file under the tests/ directory that uses such fixtures.

Applied to files:

  • tests/e2e/billing/override/test_async_override.py
  • tests/e2e/billing/override/test_sync_override.py
🧬 Code graph analysis (1)
tests/e2e/billing/override/test_sync_override.py (5)
mpt_api_client/exceptions.py (1)
  • MPTAPIError (20-42)
mpt_api_client/rql/query_builder.py (1)
  • RQLQuery (115-524)
tests/e2e/conftest.py (1)
  • mpt_ops (31-32)
tests/e2e/billing/override/conftest.py (2)
  • billing_override_id (5-6)
  • invalid_billing_override_id (10-11)
mpt_api_client/models/model.py (1)
  • id (119-121)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (9)
e2e_config.test.json (1)

24-24: LGTM!

The new billing override ID follows the established naming convention and is properly placed within the billing configuration section. Based on learnings, this ID is intentional as it comes from seeded test data.

tests/e2e/billing/override/test_async_override.py (4)

9-12: LGTM!

The test correctly uses async/await and verifies the basic get operation. Based on learnings, reusing existing API resources for read-only operations is the intended pattern for e2e tests.


15-20: LGTM!

The pagination test correctly verifies that billing overrides can be listed. The assertion assumes seeded test data exists, which is consistent with the e2e testing approach.


23-25: LGTM!

The test properly verifies 404 error handling using the invalid ID fixture and pytest's exception matching.


28-38: LGTM!

The filter test demonstrates proper use of RQLQuery chaining with field selection. The hardcoded externalId="e2e-seeded-override" is intentional per learnings, as it comes from seeded test data.

tests/e2e/billing/override/test_sync_override.py (4)

9-12: LGTM!

The synchronous get test correctly mirrors its async counterpart and properly uses the sync client fixture.


15-20: LGTM!

The pagination test correctly verifies synchronous listing of billing overrides.


23-25: LGTM!

The 404 error handling test is correctly implemented for the synchronous client.


28-38: LGTM!

The filter test correctly uses synchronous iteration with list() and maintains consistency with the async version's filter logic.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
tests/e2e/billing/override/test_async_override.py (2)

9-12: Consider strengthening the assertion.

The test only verifies that result is not None. Consider also asserting that result.id == billing_override_id to confirm the correct resource was retrieved.

💡 Suggested enhancement
 async def test_get_billing_override_by_id(async_mpt_ops, billing_override_id):
     result = await async_mpt_ops.billing.manual_overrides.get(billing_override_id)
 
     assert result is not None
+    assert result.id == billing_override_id

28-38: Extract hardcoded externalId to a named constant.

Line 32 uses the hardcoded string "e2e-seeded-override". Based on learnings, hardcoded external IDs in e2e tests are intentional due to seeded test data, but should be extracted to a named constant (e.g., E2E_OVERRIDE_EXTERNAL_ID) and documented as depending on seed data to avoid brittle tests.

♻️ Suggested refactor

At the top of the file, after imports:

+# External ID from seeded test data - must match seed configuration
+E2E_OVERRIDE_EXTERNAL_ID = "e2e-seeded-override"
+
 pytestmark = [pytest.mark.flaky]

Then update line 32:

     filtered_billing_overrides = (
         mpt_ops.billing.manual_overrides.filter(RQLQuery(id=billing_override_id))
-        .filter(RQLQuery(externalId="e2e-seeded-override"))
+        .filter(RQLQuery(externalId=E2E_OVERRIDE_EXTERNAL_ID))
         .select(*select_fields)
     )
tests/e2e/billing/override/test_sync_override.py (2)

9-12: Consider strengthening the assertion.

The test only verifies that result is not None. Consider also asserting that result.id == billing_override_id to confirm the correct resource was retrieved.

💡 Suggested enhancement
 def test_get_billing_override_by_id(mpt_ops, billing_override_id):
     result = mpt_ops.billing.manual_overrides.get(billing_override_id)
 
     assert result is not None
+    assert result.id == billing_override_id

28-38: Extract hardcoded externalId to a named constant.

Line 32 uses the hardcoded string "e2e-seeded-override". Based on learnings, hardcoded external IDs in e2e tests are intentional due to seeded test data, but should be extracted to a named constant (e.g., E2E_OVERRIDE_EXTERNAL_ID) and documented as depending on seed data to avoid brittle tests.

♻️ Suggested refactor

At the top of the file, after imports:

+# External ID from seeded test data - must match seed configuration
+E2E_OVERRIDE_EXTERNAL_ID = "e2e-seeded-override"
+
 pytestmark = [pytest.mark.flaky]

Then update line 32:

     filtered_billing_overrides = (
         mpt_ops.billing.manual_overrides.filter(RQLQuery(id=billing_override_id))
-        .filter(RQLQuery(externalId="e2e-seeded-override"))
+        .filter(RQLQuery(externalId=E2E_OVERRIDE_EXTERNAL_ID))
         .select(*select_fields)
     )
📜 Review details

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b2801fc and 02f32fc.

📒 Files selected for processing (4)
  • e2e_config.test.json
  • tests/e2e/billing/override/conftest.py
  • tests/e2e/billing/override/test_async_override.py
  • tests/e2e/billing/override/test_sync_override.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*

⚙️ CodeRabbit configuration file

**/*: For each subsequent commit in this PR, explicitly verify if previous review comments have been resolved

Files:

  • tests/e2e/billing/override/test_async_override.py
  • e2e_config.test.json
  • tests/e2e/billing/override/test_sync_override.py
  • tests/e2e/billing/override/conftest.py
**/*.py

⚙️ CodeRabbit configuration file

**/*.py: Follow the linting rules defined in pyproject.toml under [tool.ruff] and [tool.flake8] sections.
For formatting, use Ruff instead of Black. Do not suggest Black formatting changes.

Files:

  • tests/e2e/billing/override/test_async_override.py
  • tests/e2e/billing/override/test_sync_override.py
  • tests/e2e/billing/override/conftest.py
🧠 Learnings (4)
📓 Common learnings
Learnt from: albertsola
Repo: softwareone-platform/mpt-api-python-client PR: 183
File: tests/e2e/catalog/price_lists/conftest.py:29-30
Timestamp: 2026-01-08T08:34:13.551Z
Learning: In the mpt-api-python-client E2E tests, the team intentionally reuses existing API resources (via e2e_config) for read-only operations and safe mutations (e.g., updating the "notes" field) to improve test execution speed. Only destructive/dangerous tests use isolated fixtures (created_price_list or async_created_price_list) that are created and cleaned up per test.
📚 Learning: 2026-01-08T08:34:05.465Z
Learnt from: albertsola
Repo: softwareone-platform/mpt-api-python-client PR: 183
File: tests/e2e/catalog/price_lists/conftest.py:29-30
Timestamp: 2026-01-08T08:34:05.465Z
Learning: In end-to-end tests (e.g., tests/e2e/...), reuse existing API resources for read-only operations and safe mutations to speed up test execution. Reserve isolated fixtures (e.g., created_price_list) for destructive tests that require per-test creation and cleanup. Ensure tests document when a fixture creates/destroys data and clearly indicate which operations are destructive, so tests stay fast and properly isolated.

Applied to files:

  • tests/e2e/billing/override/test_async_override.py
  • tests/e2e/billing/override/test_sync_override.py
  • tests/e2e/billing/override/conftest.py
📚 Learning: 2026-01-08T23:38:19.565Z
Learnt from: robcsegal
Repo: softwareone-platform/mpt-api-python-client PR: 186
File: tests/e2e/billing/ledger/charge/test_sync_ledger_charge.py:33-39
Timestamp: 2026-01-08T23:38:19.565Z
Learning: In Python e2e tests under tests/e2e, hardcoded external IDs (e.g., INV12345) are intentional because they come from seeded test data. Ensure the test data seeds consistently include these IDs; if seeds change, update tests accordingly. Prefer using a named constant for such IDs (e.g., INV_EXTERNAL_ID) and document the dependency on seed data to avoid brittle tests.

Applied to files:

  • tests/e2e/billing/override/test_async_override.py
  • tests/e2e/billing/override/test_sync_override.py
  • tests/e2e/billing/override/conftest.py
📚 Learning: 2025-12-12T15:02:20.732Z
Learnt from: robcsegal
Repo: softwareone-platform/mpt-api-python-client PR: 160
File: tests/e2e/commerce/agreement/attachment/test_async_agreement_attachment.py:55-58
Timestamp: 2025-12-12T15:02:20.732Z
Learning: In pytest with pytest-asyncio, if a test function uses async fixtures but contains no await, declare the test function as def (synchronous) instead of async def. Pytest-asyncio will resolve the async fixtures automatically; this avoids linter complaints about unnecessary async functions. This pattern applies to any test file under the tests/ directory that uses such fixtures.

Applied to files:

  • tests/e2e/billing/override/test_async_override.py
  • tests/e2e/billing/override/test_sync_override.py
  • tests/e2e/billing/override/conftest.py
🧬 Code graph analysis (3)
tests/e2e/billing/override/test_async_override.py (5)
mpt_api_client/exceptions.py (1)
  • MPTAPIError (20-42)
mpt_api_client/rql/query_builder.py (1)
  • RQLQuery (115-524)
tests/e2e/conftest.py (1)
  • async_mpt_ops (36-39)
tests/e2e/billing/override/conftest.py (2)
  • billing_override_id (5-6)
  • invalid_billing_override_id (10-11)
mpt_api_client/models/model.py (1)
  • id (119-121)
tests/e2e/billing/override/test_sync_override.py (5)
mpt_api_client/exceptions.py (1)
  • MPTAPIError (20-42)
mpt_api_client/rql/query_builder.py (1)
  • RQLQuery (115-524)
tests/e2e/conftest.py (1)
  • mpt_ops (31-32)
tests/e2e/billing/override/conftest.py (2)
  • billing_override_id (5-6)
  • invalid_billing_override_id (10-11)
mpt_api_client/models/model.py (1)
  • id (119-121)
tests/e2e/billing/override/conftest.py (1)
tests/e2e/conftest.py (1)
  • e2e_config (89-92)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (4)
e2e_config.test.json (1)

24-24: LGTM!

The billing override ID configuration follows the established pattern and correctly supports the new test fixtures.

tests/e2e/billing/override/conftest.py (1)

4-11: LGTM!

Both fixtures follow established e2e testing patterns: billing_override_id reuses existing seeded data for read-only operations (speeding up test execution), and invalid_billing_override_id provides a deterministic invalid value for negative testing.

Based on learnings, reusing existing API resources via fixtures like these is the preferred approach for e2e tests.

tests/e2e/billing/override/test_async_override.py (1)

6-6: Verify the necessity of marking all tests as flaky.

All tests in this module are marked with pytest.mark.flaky. Per coding guidelines, this marker should indicate intermittent stability concerns. Are these tests known to be unstable, or is this marker preemptive? If instability is expected, please document the root cause.

Consider investigating and resolving the underlying instability rather than marking tests flaky, or remove the marker if tests prove stable.

tests/e2e/billing/override/test_sync_override.py (1)

6-6: Verify the necessity of marking all tests as flaky.

All tests in this module are marked with pytest.mark.flaky. Per coding guidelines, this marker should indicate intermittent stability concerns. Are these tests known to be unstable, or is this marker preemptive? If instability is expected, please document the root cause.

Consider investigating and resolving the underlying instability rather than marking tests flaky, or remove the marker if tests prove stable.

@robcsegal robcsegal force-pushed the MPT-14926-add-e-2-e-tests-for-billing-overrides branch from 02f32fc to 1ec8ae9 Compare January 12, 2026 12:39
@sonarqubecloud
Copy link

@robcsegal robcsegal merged commit 9879263 into main Jan 12, 2026
4 of 5 checks passed
@robcsegal robcsegal deleted the MPT-14926-add-e-2-e-tests-for-billing-overrides branch January 12, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants