Skip to content

Conversation

@kruai
Copy link
Collaborator

@kruai kruai commented Dec 1, 2025

This PR is being opened to suggest a refactor for test_host_app_mq_service.py for PR #3204.

Summary by Sourcery

Refactor host application message consumer tests to use a unified, parameterized suite covering all application types.

Tests:

  • Introduce shared application test data configuration to drive parameterized tests for all host app data models.
  • Replace per-application test classes with generic parameterized tests for create, update, and batch processing scenarios across all applications.

@kruai kruai requested a review from a team as a code owner December 1, 2025 14:08
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Dec 1, 2025

Reviewer's Guide

Refactors host app MQ service tests to use a single parametrized test suite that covers all application types (advisor, vulnerability, patch, remediations, compliance, malware, image_builder) for upsert, update, and batch-processing behavior, using shared test data configuration and generic assertions per model.

File-Level Changes

Change Details Files
Introduce shared application test data configuration used to drive parametrized tests for all application types.
  • Add APPLICATION_TEST_DATA constant with per-application tuples: name, model class, sample payload, and fields to assert.
  • Include application-specific nuances in the test data, such as timestamps for last_scan and differing verification subsets for some models.
tests/test_host_app_mq_service.py
Replace multiple per-application test classes with a single parametrized test class that generically tests upsert of new records, updates of existing records, and batch processing.
  • Create TestHostAppMessageConsumerAllApplications using pytest.mark.parametrize over APPLICATION_TEST_DATA.
  • Generalize upsert-new-record test to send sample_data via create_host_app_message, set the application header from app_name, query the appropriate model_class, and assert specified fields plus last_updated when present.
  • Generalize upsert-update-record test to first insert sample_data, then compute updated_data by incrementing integer fields and prefixing most string fields, and assert corresponding changes on the persisted record.
  • Generalize batch-processing test to send two hosts in a single message (one with sample_data and one with a slightly modified copy) and assert both records exist and differ on at least one numeric field.
tests/test_host_app_mq_service.py
Remove now-redundant, application-specific test classes and methods that duplicated similar logic for each model.
  • Delete TestHostAppMessageConsumerAdvisor, Vulnerability, Patch, Remediations, Compliance, Malware, and ImageBuilder classes and their per-app test methods for upsert and batch behavior.
  • Rely on the consolidated parametrized tests to cover the same functionality across all supported application types.
tests/test_host_app_mq_service.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • In test_batch_processing, relying on first_field = list(fields_to_verify.keys())[0] makes the assertion a bit fragile and only checks one field; consider iterating over all fields_to_verify to validate both hosts’ persisted data more thoroughly and avoid depending on dict key order.
  • The comment # Create data for second host (slightly different values) in test_batch_processing doesn’t always hold because max(1, value - 2) can leave the value unchanged (e.g. when value == 1); either adjust the transformation to guarantee a different value or update the comment to match the behavior.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `test_batch_processing`, relying on `first_field = list(fields_to_verify.keys())[0]` makes the assertion a bit fragile and only checks one field; consider iterating over all `fields_to_verify` to validate both hosts’ persisted data more thoroughly and avoid depending on dict key order.
- The comment `# Create data for second host (slightly different values)` in `test_batch_processing` doesn’t always hold because `max(1, value - 2)` can leave the value unchanged (e.g. when `value == 1`); either adjust the transformation to guarantee a different value or update the comment to match the behavior.

## Individual Comments

### Comment 1
<location> `tests/test_host_app_mq_service.py:26-35` </location>
<code_context>
+        },
+        {"total_cves": 50, "critical_cves": 5, "high_severity_cves": 10},
+    ),
+    (
+        "patch",
+        HostAppDataPatch,
+        {"installable_advisories": 15, "template": "baseline-template", "rhsm_locked_version": "9.4"},
+        {"installable_advisories": 15, "template": "baseline-template", "rhsm_locked_version": "9.4"},
+    ),
+    (
+        "remediations",
+        HostAppDataRemediations,
+        {"remediations_plans": 7},
+        {"remediations_plans": 7},
+    ),
+    (
+        "compliance",
+        HostAppDataCompliance,
+        {"policies": 3, "last_scan": datetime.now(UTC).isoformat()},
</code_context>

<issue_to_address>
**issue (testing):** Compliance tests no longer assert that `last_scan` is persisted

Previously, `HostAppDataCompliance.last_scan` was asserted to be non-`None`, but in the refactored tests it’s no longer verified because `last_scan` is omitted from `fields_to_verify` for the `"compliance"` entry. To preserve coverage and catch regressions in timestamp handling, please either add `"last_scan"` to `fields_to_verify` (and assert equality) or add an explicit `assert app_data.last_scan is not None` in the compliance branch of `test_upsert_new_record` (analogous to the `last_updated` check for advisor).
</issue_to_address>

### Comment 2
<location> `tests/test_host_app_mq_service.py:249-253` </location>
<code_context>
-        assert app_data is not None
-        assert app_data.image_name == "rhel-9-base"
-        assert app_data.image_status == "active"
+        # Verify first host has original data
+        first_field = list(fields_to_verify.keys())[0]
+        assert getattr(app_data1, first_field) == sample_data[first_field]
+        # Verify second host has different data (for numeric fields)
+        if isinstance(sample_data[first_field], int):
+            assert getattr(app_data2, first_field) == data2[first_field]

</code_context>

<issue_to_address>
**issue (testing):** Batch test does not actually validate second-host data for malware and image_builder

In `test_batch_processing`, only the first field in `fields_to_verify` is checked, and the second-host assertion only runs when that field is an `int`. For malware (`"last_status"`) and image_builder (`"image_name"`), the first field is a `str`, so we never validate host2’s values against `data2`, only that `app_data2` exists. To make these tests meaningful, iterate over all fields in `fields_to_verify` and, for numeric fields, assert that host2’s value equals `data2[field]` and differs from host1’s. That will properly verify per-host data isolation for all applications.
</issue_to_address>

### Comment 3
<location> `tests/test_host_app_mq_service.py:169-170` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid loops in tests. ([`no-loop-in-tests`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/no-loop-in-tests))

<details><summary>Explanation</summary>Avoid complex code, like loops, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:
* loops
* conditionals

Some ways to fix this:

* Use parametrized tests to get rid of the loop.
* Move the complex logic into helpers.
* Move the complex part into pytest fixtures.

> Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / [Don't Put Logic in Tests](https://abseil.io/resources/swe-book/html/ch12.html#donapostrophet_put_logic_in_tests)
</details>
</issue_to_address>

### Comment 4
<location> `tests/test_host_app_mq_service.py:172-173` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid conditionals in tests. ([`no-conditionals-in-tests`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/no-conditionals-in-tests))

<details><summary>Explanation</summary>Avoid complex code, like conditionals, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:
* loops
* conditionals

Some ways to fix this:

* Use parametrized tests to get rid of the loop.
* Move the complex logic into helpers.
* Move the complex part into pytest fixtures.

> Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / [Don't Put Logic in Tests](https://abseil.io/resources/swe-book/html/ch12.html#donapostrophet_put_logic_in_tests)
</details>
</issue_to_address>

### Comment 5
<location> `tests/test_host_app_mq_service.py:192-196` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid loops in tests. ([`no-loop-in-tests`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/no-loop-in-tests))

<details><summary>Explanation</summary>Avoid complex code, like loops, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:
* loops
* conditionals

Some ways to fix this:

* Use parametrized tests to get rid of the loop.
* Move the complex logic into helpers.
* Move the complex part into pytest fixtures.

> Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / [Don't Put Logic in Tests](https://abseil.io/resources/swe-book/html/ch12.html#donapostrophet_put_logic_in_tests)
</details>
</issue_to_address>

### Comment 6
<location> `tests/test_host_app_mq_service.py:193-196` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid conditionals in tests. ([`no-conditionals-in-tests`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/no-conditionals-in-tests))

<details><summary>Explanation</summary>Avoid complex code, like conditionals, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:
* loops
* conditionals

Some ways to fix this:

* Use parametrized tests to get rid of the loop.
* Move the complex logic into helpers.
* Move the complex part into pytest fixtures.

> Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / [Don't Put Logic in Tests](https://abseil.io/resources/swe-book/html/ch12.html#donapostrophet_put_logic_in_tests)
</details>
</issue_to_address>

### Comment 7
<location> `tests/test_host_app_mq_service.py:208-214` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid loops in tests. ([`no-loop-in-tests`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/no-loop-in-tests))

<details><summary>Explanation</summary>Avoid complex code, like loops, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:
* loops
* conditionals

Some ways to fix this:

* Use parametrized tests to get rid of the loop.
* Move the complex logic into helpers.
* Move the complex part into pytest fixtures.

> Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / [Don't Put Logic in Tests](https://abseil.io/resources/swe-book/html/ch12.html#donapostrophet_put_logic_in_tests)
</details>
</issue_to_address>

### Comment 8
<location> `tests/test_host_app_mq_service.py:211-214` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid conditionals in tests. ([`no-conditionals-in-tests`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/no-conditionals-in-tests))

<details><summary>Explanation</summary>Avoid complex code, like conditionals, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:
* loops
* conditionals

Some ways to fix this:

* Use parametrized tests to get rid of the loop.
* Move the complex logic into helpers.
* Move the complex part into pytest fixtures.

> Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / [Don't Put Logic in Tests](https://abseil.io/resources/swe-book/html/ch12.html#donapostrophet_put_logic_in_tests)
</details>
</issue_to_address>

### Comment 9
<location> `tests/test_host_app_mq_service.py:227-229` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid loops in tests. ([`no-loop-in-tests`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/no-loop-in-tests))

<details><summary>Explanation</summary>Avoid complex code, like loops, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:
* loops
* conditionals

Some ways to fix this:

* Use parametrized tests to get rid of the loop.
* Move the complex logic into helpers.
* Move the complex part into pytest fixtures.

> Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / [Don't Put Logic in Tests](https://abseil.io/resources/swe-book/html/ch12.html#donapostrophet_put_logic_in_tests)
</details>
</issue_to_address>

### Comment 10
<location> `tests/test_host_app_mq_service.py:228-229` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid conditionals in tests. ([`no-conditionals-in-tests`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/no-conditionals-in-tests))

<details><summary>Explanation</summary>Avoid complex code, like conditionals, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:
* loops
* conditionals

Some ways to fix this:

* Use parametrized tests to get rid of the loop.
* Move the complex logic into helpers.
* Move the complex part into pytest fixtures.

> Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / [Don't Put Logic in Tests](https://abseil.io/resources/swe-book/html/ch12.html#donapostrophet_put_logic_in_tests)
</details>
</issue_to_address>

### Comment 11
<location> `tests/test_host_app_mq_service.py:253-254` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid conditionals in tests. ([`no-conditionals-in-tests`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/no-conditionals-in-tests))

<details><summary>Explanation</summary>Avoid complex code, like conditionals, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:
* loops
* conditionals

Some ways to fix this:

* Use parametrized tests to get rid of the loop.
* Move the complex logic into helpers.
* Move the complex part into pytest fixtures.

> Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / [Don't Put Logic in Tests](https://abseil.io/resources/swe-book/html/ch12.html#donapostrophet_put_logic_in_tests)
</details>
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +249 to +253
# Verify first host has original data
first_field = list(fields_to_verify.keys())[0]
assert getattr(app_data1, first_field) == sample_data[first_field]
# Verify second host has different data (for numeric fields)
if isinstance(sample_data[first_field], int):
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (testing): Batch test does not actually validate second-host data for malware and image_builder

In test_batch_processing, only the first field in fields_to_verify is checked, and the second-host assertion only runs when that field is an int. For malware ("last_status") and image_builder ("image_name"), the first field is a str, so we never validate host2’s values against data2, only that app_data2 exists. To make these tests meaningful, iterate over all fields in fields_to_verify and, for numeric fields, assert that host2’s value equals data2[field] and differs from host1’s. That will properly verify per-host data isolation for all applications.

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.

2 participants