Skip to content

Refactor: Modularize ApiResponseHelper#createUsageResponse - #13490

Open
PrashantBhanage wants to merge 1 commit into
apache:mainfrom
PrashantBhanage:fix-11635-refactor-usage
Open

PrashantBhanage wants to merge 1 commit into
apache:mainfrom
PrashantBhanage:fix-11635-refactor-usage

Conversation

@PrashantBhanage

@PrashantBhanage PrashantBhanage commented Jun 25, 2026 •

Copy link
Copy Markdown

Fixes #11635

Description

This PR addresses the technical debt in ApiResponseHelper#createUsageResponse(Usage) by modularizing the 530-line method.

  • Extracted the 500+ line switch/if-else block into a main dispatcher method populateUsageTypeSpecificDetails.
  • Created 18 individual private helper methods for each specific UsageType to improve maintainability and readability.
  • Introduced a UsageResourceDetails container class to manage and return resourceId and resourceType for tag lookups.
  • The refactor is structural. The small behavior fixes are listed below.

Additional Changes

  • Added JUnit Jupiter, JUnit Vintage and mockito-junit-jupiter test dependencies to server/pom.xml to support JUnit 5 tests.
  • Migrated ApiResponseHelperTest from JUnit 4 to JUnit 5 and added unit tests for the extracted helper methods.
  • Replaced Boolean.getBoolean with Boolean.parseBoolean where a string value was being parsed.
  • Added null checks for the service offering and for nullable values passed to toHumanReadableSize.
  • Removed an unused variable.

Types of changes

  • Cleanup (Code refactoring and cleanup, that may add test cases)
  • Test (unit or integration test code)

How Has This Been Tested?

  • mvn -pl server -Dtest=ApiResponseHelperTest test on the branch rebased onto current main: 44 tests, 0 failures, 0 errors
  • Checkstyle passes

@boring-cyborg

boring-cyborg Bot commented Jun 25, 2026

Copy link
Copy Markdown

Congratulations on your first Pull Request and welcome to the Apache CloudStack community! If you have any issues or are unsure about any anything please check our Contribution Guide (https://github.com/apache/cloudstack/blob/main/CONTRIBUTING.md)
Here are some useful points:

@sureshanaparti

Copy link
Copy Markdown
Contributor

@blueorangutan package

@codecov

codecov Bot commented Jun 25, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 64.12826% with 179 lines in your changes missing coverage. Please review.
✅ Project coverage is 19.97%. Comparing base (7ed0cec) to head (e64c939).
⚠️ Report is 71 commits behind head on main.

Files with missing lines Patch % Lines
...src/main/java/com/cloud/api/ApiResponseHelper.java 64.12% 123 Missing and 56 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main   #13490      +/-   ##
============================================
+ Coverage     19.91%   19.97%   +0.06%     
- Complexity    20198    20290      +92     
============================================
  Files          6373     6373              
  Lines        577230   577325      +95     
  Branches      70696    70704       +8     
============================================
+ Hits         114936   115309     +373     
+ Misses       449736   449418     -318     
- Partials      12558    12598      +40     
Flag Coverage Δ
uitests 3.71% <ø> (ø)
unittests 21.24% <64.12%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@PrashantBhanage

Copy link
Copy Markdown
Author

Added unit tests for all 18 extracted UsageType helper methods to address the coverage concern. Also added the required JUnit Jupiter and mockito-junit-jupiter test dependencies to server/pom.xml. All 41 tests pass locally.

@PrashantBhanage PrashantBhanage left a comment •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I don't know where the problem is.

@DaanHoogland

Copy link
Copy Markdown
Contributor

I don't know where the problem is.

what problem are you talking about, @PrashantBhanage ?

I only see an integration test failure which seems unrelated.

@PrashantBhanage

Copy link
Copy Markdown
Author

I don't know where the problem is.

what problem are you talking about, @PrashantBhanage ?

I only see an integration test failure which seems unrelated.

Got it, thanks! I raised #13516 for the flaky test separately. The refactor itself should be good.

@DaanHoogland

Copy link
Copy Markdown
Contributor

@blueorangutan test

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors ApiResponseHelper#createUsageResponse(Usage) by extracting usage-type-specific logic into a dispatcher (populateUsageTypeSpecificDetails) plus multiple private helper methods, introducing a small container (UsageResourceDetails) to carry resourceId/resourceType for tag lookups.

Changes:

  • Modularized usage-response population into dedicated helper methods keyed by UsageTypes.
  • Updated ApiResponseHelperTest to JUnit 5 + Mockito Jupiter and added focused tests for several usage-type helpers.
  • Added JUnit Jupiter / Vintage and Mockito Jupiter test dependencies to the server module POM.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 14 comments.

File Description
server/src/main/java/com/cloud/api/ApiResponseHelper.java Extracts usage-type logic into helper methods and centralizes tag lookup via UsageResourceDetails.
server/src/test/java/com/cloud/api/ApiResponseHelperTest.java Migrates to JUnit 5/Mockito Jupiter and adds unit tests for the new helper methods via reflection.
server/pom.xml Adds JUnit 5 (Jupiter + Vintage) and Mockito Jupiter dependencies to support the test migration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread server/src/main/java/com/cloud/api/ApiResponseHelper.java
Comment thread server/src/main/java/com/cloud/api/ApiResponseHelper.java Outdated
Comment thread server/src/main/java/com/cloud/api/ApiResponseHelper.java Outdated
Comment thread server/src/main/java/com/cloud/api/ApiResponseHelper.java Outdated
Comment thread server/src/main/java/com/cloud/api/ApiResponseHelper.java Outdated
Comment on lines 4504 to +4506
if (tmpl != null) {
usageRecResponse.setUsageId(tmpl.getUuid());
resourceId = tmpl.getId();
}
//Template/ISO Size
usageRecResponse.setSize(usageRecord.getSize());
if (usageRecord.getUsageType() == UsageTypes.ISO) {
usageRecResponse.setVirtualSize(usageRecord.getSize());
resourceType = ResourceObjectType.ISO;
} else {
usageRecResponse.setVirtualSize(usageRecord.getVirtualSize());
resourceType = ResourceObjectType.Template;
}
if (!oldFormat) {
final StringBuilder builder = new StringBuilder();
if (usageRecord.getUsageType() == UsageTypes.TEMPLATE) {
builder.append("Template usage");
} else if (usageRecord.getUsageType() == UsageTypes.ISO) {
builder.append("ISO usage");
}
if (tmpl != null) {
builder.append(" for ").append(tmpl.getName()).append(" (").append(tmpl.getUuid()).append(") ")
.append("with size ").append(toHumanReadableSize(usageRecord.getSize())).append(" and virtual size ").append(toHumanReadableSize(usageRecord.getVirtualSize()));
}
usageRecResponse.setDescription(builder.toString());
builder.append(" for ").append(tmpl.getName()).append(" (").append(tmpl.getUuid()).append(") ")
.append("with size ").append(toHumanReadableSize(usageRecord.getSize())).append(" and virtual size ").append(toHumanReadableSize(usageRecord.getVirtualSize()));
Comment on lines 4527 to +4529
if (snap != null) {
usageRecResponse.setUsageId(snap.getUuid());
resourceId = snap.getId();
}
//Snapshot Size
usageRecResponse.setSize(usageRecord.getSize());
if (!oldFormat) {
final StringBuilder builder = new StringBuilder();
builder.append("Snapshot usage ");
if (snap != null) {
builder.append("for ").append(snap.getName()).append(" (").append(snap.getUuid()).append(") ")
.append("with size ").append(toHumanReadableSize(usageRecord.getSize()));
}
usageRecResponse.setDescription(builder.toString());
builder.append("for ").append(snap.getName()).append(" (").append(snap.getUuid()).append(") ")
.append("with size ").append(toHumanReadableSize(usageRecord.getSize()));
Comment thread server/src/main/java/com/cloud/api/ApiResponseHelper.java Outdated
Comment thread server/src/main/java/com/cloud/api/ApiResponseHelper.java
Comment thread server/src/main/java/com/cloud/api/ApiResponseHelper.java
@PrashantBhanage

Copy link
Copy Markdown
Author

Applied all the Copilot suggestions, null checks for svcOffering, nullable Long values, and removed the unused variable.

@PrashantBhanage

Copy link
Copy Markdown
Author

Fixed the build, replaced the internal X509CertImpl with standard Java API and removed the unused imports that Copilot introduced.

@PrashantBhanage

Copy link
Copy Markdown
Author

I just pushed a quick fix to add the missing EOF newline in ApiResponseHelperTest.java, so the pre-commit check should be green now.

Also, just wanted to give a heads-up that the UI Build and Sonar JaCoCo failures look unrelated to my Java changes. The UI test seems to be timing out on a Vue router test (Status.spec.js), and Sonar is just throwing a 403 permission error right at the end when trying to drop a PR comment.

Let me know if there's anything else I need to tweak!

@PrashantBhanage

Copy link
Copy Markdown
Author

It should be good now!

@DaanHoogland

Copy link
Copy Markdown
Contributor

@blueorangutan test

@Damans227 Damans227 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit: this "Refactor" PR also carries a .github/workflows/sonar-check.yml change and a server/pom.xml dependency bump (junit-jupiter/vintage/mockito-jupiter), plus a full JUnit4→JUnit5 migration of ApiResponseHelperTest. Worth calling out in the description since none of that is "modularize createUsageResponse".

Comment thread server/src/main/java/com/cloud/api/ApiResponseHelper.java Outdated
Comment thread server/src/main/java/com/cloud/api/ApiResponseHelper.java Outdated
return resourceDetails;
}

private UsageResourceDetails populateNetworkOfferingUsageResponse(Usage usageRecord, UsageRecordResponse usageRecResponse, boolean oldFormat, VMInstanceVO vmInstance) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit: this method (and populateVpnUsersUsageResponse, populateVolumeSecondaryUsageResponse, populateBucketUsageResponse below) just returns new UsageResourceDetails() directly, while the other populate* methods declare a local resourceDetails, mutate it, and return that. Minor inconsistency in the extraction pattern.

@PrashantBhanage

Copy link
Copy Markdown
Author

@Damans227 Fixed the indentation on handleCertificateResponse, added proper imports for java.security.cert classes instead of using fully-qualified names inline. Will also update the PR description to mention the pom.xml dependency additions and JUnit 5 migration.

@DaanHoogland

Copy link
Copy Markdown
Contributor

@blueorangutan package

@DaanHoogland

Copy link
Copy Markdown
Contributor

@blueorangutan test

@DaanHoogland

Copy link
Copy Markdown
Contributor

thanks @PrashantBhanage , one more, can you rebase the PR to the 4.22 LTS branch?

@PrashantBhanage

Copy link
Copy Markdown
Author

@DaanHoogland I have opened the 4.22 LTS backport PR here: [https://github.com//pull/13695]

Note: I intentionally excluded the JUnit 5 test migration from the backport to avoid framework conflicts with the stable 4.22 testing architecture, but the core backend refactor and the .toString() bug fix are included.

@PrashantBhanage

Copy link
Copy Markdown
Author

@DaanHoogland @Damans227

I went through the Copilot findings against the current main branch after syncing the PR and restored the behavior that had been missing from the refactor, including:

  • key-pair response fields
  • domain resource tags
  • port-forwarding network name
  • system VM storage IP
  • keepmacaddressonpublicnic handling
  • VPC conserve mode
  • VPN gateway parameter indicators
  • secondary-IP descriptions
  • NIC enabled state
  • usage-response dispatcher coverage

The refactor itself remains focused on modularizing
ApiResponseHelper#createUsageResponse(Usage), without intentionally changing the existing behavior.

I also addressed the two maintainer concerns that were still actionable. The remaining maintainer point was style-only, as noted.

Validation completed:

  • ApiResponseHelperTest: 5/5 passing
  • createUsageResponse dispatcher test: 1/1 passing
  • clean working tree
  • latest fixes pushed in commit 0e07fe6

Could you please take another look at the updated PR?

@Damans227

Copy link
Copy Markdown
Collaborator

Could you please take another look at the updated PR?

@PrashantBhanage my earlier points are covered and the missing response fields are back, outside the usage part it now matches main. one small difference left: network traffic records with no network attached lose the vm's tags, main still shows them. can we keep that like before?

@PrashantBhanage

Copy link
Copy Markdown
Author

@Damans227 Fixed this too — network traffic records without an attached network now retain the VM tags like main.

@Damans227

Copy link
Copy Markdown
Collaborator

network traffic records without an attached network now retain the VM tags like main

@PrashantBhanage that covers it, e64c939 sets the vm type back so those records keep the vm tags like main. thanks

@PrashantBhanage

Copy link
Copy Markdown
Author

@DaanHoogland the Sonar check seems to fail only when posting the coverage comment due to a 403 error. Both targeted and full server tests pass locally. Should we handle this separately?

@Damans227

Copy link
Copy Markdown
Collaborator

Should we handle this separately?

@PrashantBhanage yes, #14299 handles it. the 403 comes from the workflow, not this change

@github-actions

Copy link
Copy Markdown

This pull request has merge conflicts. Dear author, please fix the conflicts and sync your branch with the base branch.

response.setSubject(certificate.getSubjectDN().toString());
response.setIssuer(certificate.getIssuerDN().toString());
response.setSerialNum(certificate.getSerialNumberObject().toString());
response.setSerialNum(certificate.getSerialNumber().toString());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@PrashantBhanage any reason to change how the certificate serial number is shown here? main shows it in hex, this shows it as a plain number

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@PrashantBhanage any reason to change how the certificate serial number is shown here? main shows it in hex, this shows it as a plain number

Okk So the serial number format changed because I swapped X509CertImpl for X509Certificate. I reverted that part, so handleCertificateResponse is the same as main now.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

that covers it, thanks

@Damans227 Damans227 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

thanks @PrashantBhanage, CLGTM.

@PrashantBhanage
PrashantBhanage force-pushed the fix-11635-refactor-usage branch from 972b77d to 14fcce0 Compare October 29, 2026 16:22
@Damans227

Copy link
Copy Markdown
Collaborator

@PrashantBhanage this looks good on the code side.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

ApiResponseHelper#createUsageResponse(Usage) needs to be modularised (530 lines).

7 participants