Skip to content

Conversation

@meinaLi
Copy link
Contributor

@meinaLi meinaLi commented Nov 19, 2025

Sometimes the actual block allocation isn't in the configured test scope. Because dd_seek is used in data writes and due to the sparsity of the qcow2 format. Now adjust the size check method to fix it.

Summary by CodeRabbit

  • Tests
    • Improved incremental backup tests to better validate disk allocation and write-offset handling, enhancing reliability and accuracy of backup verification and threshold checks.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Walkthrough

This change refactors check_domblk_info in libvirt/tests/src/incremental_backup/incremental_backup_pull_mode_info.py: the signature now takes (dd_count, dd_seek) instead of (target_min, target_max). The function parses Allocation as float and Capacity in bytes (converted to MB), computes write_end_MB = dd_seek + dd_count, and derives dynamic target_min/target_max (0.8–1.2 of the expected MB, bounded by capacity). block_allocation is converted to MB as a float and compared against the derived bounds. All call sites within the file were updated to pass dd_count and dd_seek and to re-run checks when dd_seek changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

Areas requiring extra attention:

  • Dynamic bounds calculation: correctness of write_end_MB, min(capacity, write_end_MB), and 0.8–1.2 scaling.
  • Parsing and unit conversions: Allocation -> float, Capacity bytes -> MB, and MB conversions for block_allocation.
  • Call-site updates: verify every invocation supplies the correct dd_count and dd_seek semantics and any subsequent dd_seek adjustments trigger intended re-checks.
  • Edge cases: handling missing/malformed Capacity lines, precision issues from float comparisons, and behavior when expected_MB exceeds capacity.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: fixing a size check failure in the incremental backup test by refactoring the domblkinfo validation method.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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

@meinaLi
Copy link
Contributor Author

meinaLi commented Nov 19, 2025

# avocado run --vt-type libvirt --vt-omit-data-loss --vt-machine-type q35 incremental_backup.pull_mode.info
JOB ID     : c34bdaa379a87041c56ff086c0274ab61550b021
JOB LOG    : /var/log/avocado/job-results/job-2025-11-19T04.45-c34bdaa/job.log
 (1/3) type_specific.io-github-autotest-libvirt.incremental_backup.pull_mode.info.scratch_usage_info.without_datastore: STARTED
 (1/3) type_specific.io-github-autotest-libvirt.incremental_backup.pull_mode.info.scratch_usage_info.without_datastore: PASS (71.86 s)
 (2/3) type_specific.io-github-autotest-libvirt.incremental_backup.pull_mode.info.scratch_usage_info.with_datastore: STARTED
 (2/3) type_specific.io-github-autotest-libvirt.incremental_backup.pull_mode.info.scratch_usage_info.with_datastore: PASS (79.65 s)
 (3/3) type_specific.io-github-autotest-libvirt.incremental_backup.pull_mode.info.domblkinfo.without_datastore: STARTED
 (3/3) type_specific.io-github-autotest-libvirt.incremental_backup.pull_mode.info.domblkinfo.without_datastore: PASS (71.88 s)
RESULTS    : PASS 3 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 0
JOB HTML   : /var/log/avocado/job-results/job-2025-11-19T04.45-c34bdaa/results.html
JOB TIME   : 226.63 s

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
libvirt/tests/src/incremental_backup/incremental_backup_pull_mode_info.py (1)

128-147: Harden check_domblk_info against parsing issues and update the docstring

Right now block_allocation and disk_capacity_bytes are only set inside the loop that parses domblkinfo output. If for any reason the output format changes or a line is missing, this will raise UnboundLocalError instead of a clear test failure. The docstring also still documents the old target_min/target_max parameters.

Consider initializing the parsed values to None, validating them after the loop, and updating the docstring to the new parameters:

-    def check_domblk_info(dd_count, dd_seek):
-        """
-        Check the domblk info.
-
-        :params target_min: the min value of the block allocation
-        :params target_max: the max value of the block allocation
-        """
-        test.log.debug("TEST STEP: check the domblk info")
-        domblk_output = virsh.domblkinfo(vm_name, target_disk, debug=True)
-        for line in domblk_output.stdout_text.splitlines():
-            if "Allocation" in line:
-                block_allocation = float(line.split(":")[-1].strip())
-            if "Capacity" in line:
-                disk_capacity_bytes = float(line.split(":")[-1].strip())
-        capacity_MB = disk_capacity_bytes / 1024 / 1024
-        write_end_MB = int(dd_seek) + int(dd_count)
-        expected_MB = min(write_end_MB, capacity_MB)
-        target_min = expected_MB * 0.8
-        target_max = expected_MB * 1.2
-        block_allocation = block_allocation / 1024 / 1024
+    def check_domblk_info(dd_count, dd_seek):
+        """
+        Check the domblk info.
+
+        :param dd_count: dd block count used when writing to the disk (in MiB)
+        :param dd_seek: dd seek offset used when writing to the disk (in MiB)
+        """
+        test.log.debug("TEST STEP: check the domblk info")
+        domblk_output = virsh.domblkinfo(vm_name, target_disk, debug=True)
+
+        block_allocation_bytes = None
+        disk_capacity_bytes = None
+        for line in domblk_output.stdout_text.splitlines():
+            if "Allocation" in line:
+                block_allocation_bytes = float(line.split(":")[-1].strip())
+            if "Capacity" in line:
+                disk_capacity_bytes = float(line.split(":")[-1].strip())
+
+        if block_allocation_bytes is None or disk_capacity_bytes is None:
+            test.fail("Failed to parse Allocation/Capacity from domblkinfo output: %s"
+                      % domblk_output.stdout_text)
+
+        capacity_MB = disk_capacity_bytes / 1024 / 1024
+        write_end_MB = int(dd_seek) + int(dd_count)
+        expected_MB = min(write_end_MB, capacity_MB)
+        target_min = expected_MB * 0.8
+        target_max = expected_MB * 1.2
+        block_allocation = block_allocation_bytes / 1024 / 1024

This keeps the new capacity-aware logic but makes failures deterministic and easier to debug, and the docstring matches the actual API.

🧹 Nitpick comments (1)
libvirt/tests/src/incremental_backup/incremental_backup_pull_mode_info.py (1)

51-58: Keep dd_count/dd_seek usage consistent with the actual dd writes

check_domblk_info now derives expectations from dd_count and dd_seek, but write_datas still hardcodes count="200", and dd_seek is used as a string first ("0") and then an int (300). This works today but makes the test fragile if parameters change.

To keep everything in sync and avoid surprises, consider:

  • Passing dd_count into write_datas and using it instead of the literal "200".
  • Treating dd_seek as an int everywhere and converting to str only when building the dd command.

For example:

-    def write_datas(dd_seek):
+    def write_datas(dd_seek, dd_count):
         """
         Write datas to the disk in guest.
         """
         vm_session = vm.wait_for_login()
         new_disk = libvirt_disk.get_non_root_disk_name(vm_session)[0]
-        utils_disk.dd_data_to_vm_disk(vm_session, "/dev/%s" % new_disk, seek=dd_seek, count="200")
+        utils_disk.dd_data_to_vm_disk(vm_session, "/dev/%s" % new_disk,
+                                      seek=str(dd_seek), count=str(dd_count))
         vm_session.close()
@@
-    dd_count = int(params.get("dd_count"))
+    dd_count = int(params.get("dd_count"))
@@
-    dd_seek = "0"
+    dd_seek = 0
@@
-        write_datas(dd_seek)
+        write_datas(dd_seek, dd_count)
@@
-            check_domblk_info(dd_count, dd_seek)
-            dd_seek = 300
-            write_datas(dd_seek)
-            check_domblk_info(dd_count, dd_seek)
+            check_domblk_info(dd_count, dd_seek)
+            dd_seek = 300
+            write_datas(dd_seek, dd_count)
+            check_domblk_info(dd_count, dd_seek)
@@
-            check_domblk_info(dd_count, dd_seek)
+            check_domblk_info(dd_count, dd_seek)

This keeps the new size-check behaviour but makes it much clearer that dd parameters and expectations are aligned, and avoids implicit type changes on dd_seek.

Also applies to: 128-147, 167-169, 177-177, 190-195

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 875c970 and 74c8d04.

📒 Files selected for processing (1)
  • libvirt/tests/src/incremental_backup/incremental_backup_pull_mode_info.py (4 hunks)
⏰ 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). (4)
  • GitHub Check: Python 3.8
  • GitHub Check: Python 3.11
  • GitHub Check: Python 3.12
  • GitHub Check: Python 3.9

"""
Check the domblk info.
:params target_min: the min value of the block allocation
Copy link
Contributor

Choose a reason for hiding this comment

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

Please update docstring. Others LGTM.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Finish to update the docstring, thanks.

Sometimes the actual block allocation isn't in the configured test
scope. Because dd_seek is used in data writes and due to the sparsity of
the qcow2 format. Now adjust the size check method to fix it.

Signed-off-by: Meina Li <meili@redhat.com>
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: 1

🧹 Nitpick comments (1)
libvirt/tests/src/incremental_backup/incremental_backup_pull_mode_info.py (1)

174-174: Inconsistent type for dd_seek: string vs integer.

dd_seek is initialized as a string "0" at line 174, but reassigned to an integer 300 at line 195. While the int() casts in check_domblk_info (line 147) handle this, the inconsistency could cause issues elsewhere (e.g., in write_datas which passes dd_seek to utils_disk.dd_data_to_vm_disk).

Consider using a consistent type:

-    dd_seek = "0"
+    dd_seek = 0

or:

-            dd_seek = 300
+            dd_seek = "300"

Also applies to: 195-195

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 74c8d04 and 40be6fc.

📒 Files selected for processing (1)
  • libvirt/tests/src/incremental_backup/incremental_backup_pull_mode_info.py (3 hunks)
⏰ 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). (4)
  • GitHub Check: Python 3.12
  • GitHub Check: Python 3.9
  • GitHub Check: Python 3.11
  • GitHub Check: Python 3.8
🔇 Additional comments (2)
libvirt/tests/src/incremental_backup/incremental_backup_pull_mode_info.py (2)

128-138: Docstring updated as requested.

The function signature and docstring now clearly document the new parameters dd_count and dd_seek, along with the expected behavior and error conditions. This addresses the previous review feedback.


146-154: Logic correctly handles dd_seek offset and qcow2 sparsity.

The calculation properly accounts for:

  • The actual write endpoint (dd_seek + dd_count)
  • Disk capacity as an upper bound
  • A ±20% tolerance for qcow2 format overhead/sparsity

This addresses the PR objective of fixing size check failures when dd_seek is used.

Comment on lines 141 to +151
for line in domblk_output.stdout_text.splitlines():
if "Allocation" in line:
block_allocation = int(line.split(":")[-1].strip())
block_allocation = float(line.split(":")[-1].strip())
if "Capacity" in line:
disk_capacity_bytes = float(line.split(":")[-1].strip())
capacity_MB = disk_capacity_bytes / 1024 / 1024
write_end_MB = int(dd_seek) + int(dd_count)
expected_MB = min(write_end_MB, capacity_MB)
target_min = expected_MB * 0.8
target_max = expected_MB * 1.2
block_allocation = block_allocation / 1024 / 1024
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential NameError if domblkinfo output is missing expected fields.

If the domblkinfo output lacks "Allocation" or "Capacity" lines, block_allocation or disk_capacity_bytes will be unbound, causing a NameError at line 146 or 151. Consider initializing these variables before the loop or adding a guard.

         test.log.debug("TEST STEP: check the domblk info")
         domblk_output = virsh.domblkinfo(vm_name, target_disk, debug=True)
+        block_allocation = None
+        disk_capacity_bytes = None
         for line in domblk_output.stdout_text.splitlines():
             if "Allocation" in line:
                 block_allocation = float(line.split(":")[-1].strip())
             if "Capacity" in line:
                 disk_capacity_bytes = float(line.split(":")[-1].strip())
+        if block_allocation is None or disk_capacity_bytes is None:
+            test.fail("Failed to parse Allocation or Capacity from domblkinfo output")
         capacity_MB = disk_capacity_bytes / 1024 / 1024

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In libvirt/tests/src/incremental_backup/incremental_backup_pull_mode_info.py
around lines 141 to 151, the parsing loop assumes "Allocation" and "Capacity"
are always present which can leave block_allocation or disk_capacity_bytes
undefined; initialize block_allocation and disk_capacity_bytes to None (or
sensible defaults) before the loop and after the loop check for None and either
raise a clear exception or handle the missing values (e.g., skip the test, set
defaults, or fail with a message) so you avoid a NameError and provide a
deterministic failure mode.

@meinaLi meinaLi requested a review from cliping November 27, 2025 02:19
@cliping cliping merged commit c863ad3 into autotest:master Nov 30, 2025
6 checks passed
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