Skip to content

Conversation

@SachinPremkumar
Copy link
Collaborator

@SachinPremkumar SachinPremkumar commented Jan 11, 2026

Summary by CodeRabbit

  • Tests

    • Vastly expanded unit test coverage across registration, packet management, master data, local config, and related utilities; added deletion job tests and many edge-case scenarios; improved test isolation via enhanced mocking.
  • Refactor

    • Adjusted service wiring/dependencies to reflect updated internal integrations.
  • Bug Fixes

    • Minor defensive null-safety improvements in registration flows and related validations.

Signed-off-by: sachin.sp <[email protected]>
@coderabbitai
Copy link

coderabbitai bot commented Jan 11, 2026

Walkthrough

Adds and updates unit tests across clientmanager and packetmanager modules, introduces new test coverage for a RegistrationDeletionJob, updates constructors/provider signatures to accept LocalConfigService and PacketService, adjusts several test mocks/imports, and relocates a DTO import path.

Changes

Cohort / File(s) Summary
DI & Provider Tests
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/config/AppModuleTest.java, android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/JobManagerServiceImplTest.java
Expanded mocks and updated test calls to match changed provider/constructor signatures (added LocalConfigService, PacketService) and adjusted argument orders.
New Job Tests
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/jobs/RegistrationDeletionJobTest.java
Added unit tests for RegistrationDeletionJob covering success, failure, and logging/verification flows.
Local Config Service Tests
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/LocalConfigServiceImplTest.java
Added extensive validation and delegation tests for modify/getValue/getPermittedJobs, including edge cases and permission checks.
Packet Service Tests
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PacketServiceImplTest.java
Large test additions: approval-time/export-duration/packet-count checks, deleteRegistrationPackets scenarios; updated expected repository call to updateServerStatusWithTimestamp.
Master Data Tests
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/MasterDataServiceImplTest.java
Massive test expansion (many scenarios, delta/sync flows, DTO import path updated to io.mosip.registration.clientmanager.dto.http.CACertificateResponseDto).
Registration Service & Related Tests
android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/RegistrationServiceImpl.java, android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/RegistrationServiceImplTest.java
Minor null-safety guards and formatting in implementation; tests updated to mock StorageUtils (MockedStatic) and improve isolation (setUp now throws Exception).
PreCheck / Runner Updates
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PreCheckValidatorServiceImplTest.java, .../util/*Test.java
Switched many tests to @RunWith(MockitoJUnitRunner.Silent.class); updated constructors used in tests (SyncJobDef, RegistrationCenter) and adjusted test instantiations/formatting.
Posix / Storage Tests
android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java
Replaced environment/system-property reliance with MockedStatic<StorageUtils> to control packet storage dir in tests.
Formatting / Minor Test Adjustments
multiple .../service/*Test.java, .../util/*Test.java
Formatting, whitespace, and minor stub/verification adjustments across many test files; some added lenient mocks and MockedStatic usage.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • MadhuMosip

Poem

🐇 I hopped through mocks and DTOs bright,
I stitched new tests deep into the night,
Packets pruned and configs tweaked,
Jobs that tidy, services peeked,
A rabbit cheers — the suite runs right! 🎉

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.74% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Added unit test cases' is vague and generic; it describes what was done but not what specific test cases or functionality is being tested, failing to convey meaningful information about the changeset. Revise the title to be more specific about the main test additions or improvements, such as 'Add unit tests for LocalConfigService and RegistrationDeletionJob' or 'Enhance test coverage for packet management services'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.40.5)
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/RegistrationServiceImplTest.java

[]


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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: 3

Caution

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

⚠️ Outside diff range comments (3)
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PacketServiceImplTest.java (1)

3-6: Fix mixed JUnit4/JUnit5 static imports (likely compile ambiguity on assertEquals).

You have import static org.junit.jupiter.api.Assertions.assertEquals; (Line 3) and import static org.junit.Assert.*; (Line 5), which both provide assertEquals overloads and commonly causes ambiguous resolution at compile time.

Proposed fix (pick one framework and stick to it)

If this class is JUnit4 (it uses @RunWith(MockitoJUnitRunner.class) and org.junit.Test), drop the JUnit5 static import:

-import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.Mockito.*;
 import static org.junit.Assert.*;

(Alternatively, migrate fully to JUnit5: @ExtendWith(MockitoExtension.class) + org.junit.jupiter.api.Test + remove @RunWith.)

android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/MasterDataServiceImplTest.java (2)

64-112: JUnit4 runner + JUnit5 @BeforeEach means setUp() likely never runs.

This class uses @RunWith(MockitoJUnitRunner.class) (Line 64) and org.junit.Test, but the setup uses org.junit.jupiter.api.BeforeEach (Line 106). Under JUnit4 execution, @BeforeEach won’t be invoked, so any stubbing inside setUp() may not apply.

Proposed fix (stay JUnit4)
-import org.junit.jupiter.api.BeforeEach;
+import org.junit.Before;

 ...
-    @BeforeEach
+    @Before
     public void setUp() {
         MockitoAnnotations.openMocks(this);
         when(mockContext.getString(anyInt())).thenReturn(TEST_APP_NAME);
         when(mockContext.getSharedPreferences(eq(TEST_APP_NAME), eq(Context.MODE_PRIVATE)))
                 .thenReturn(mockSharedPreferences);
     }

(Or migrate fully to JUnit5 with @ExtendWith(MockitoExtension.class) and org.junit.jupiter.api.Test.)


1335-1343: saveCACertificate test still mocks keymanager DTO; clarify intent after DTO import move.

Even after importing the HTTP CACertificateResponseDto, this test explicitly mocks io.mosip.registration.keymanager.dto.CACertificateResponseDto (Line 1335-1336). That may be correct if CertificateManagerService.uploadCACertificate(...) returns the keymanager DTO, but it’s confusing alongside the new import—especially given the identical class name.

Suggestion: either fully-qualify all CACertificateResponseDto usages in this file, or refactor imports to make the distinction obvious.

🤖 Fix all issues with AI agents
In
@android/clientmanager/src/test/java/io/mosip/registration/clientmanager/jobs/RegistrationDeletionJobTest.java:
- Around line 36-46: The timestamp verification in
testTriggerJob_SuccessfulDeletion_ReturnsTrue is brittle because
currentTimeMillis is captured before triggerJob and the production code computes
elapsed time differently; update the test to avoid exact-match timing: replace
the strict verification of logJobTransaction(jobId,
TimeUnit.MILLISECONDS.toSeconds(currentTimeMillis)) with either
verify(registrationDeletionJob).logJobTransaction(eq(jobId), anyLong()) or use
an ArgumentCaptor<Long> to capture the timestamp and assert it falls within an
expected range, or alternatively mock the time source used by
registrationDeletionJob so you can assert an exact value; ensure
packetService.deleteRegistrationPackets() is still verified and keep references
to registrationDeletionJob.triggerJob and logJobTransaction in your changes.

In
@android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/MasterDataServiceImplTest.java:
- Around line 23-24: In MasterDataServiceImplTest, remove the ambiguous wildcard
import io.mosip.registration.keymanager.dto.* and replace it with explicit
imports for only the types you actually use (or alternatively fully-qualify one
of the CACertificateResponseDto references); ensure you keep a single,
unambiguous import for CACertificateResponseDto (either
io.mosip.registration.clientmanager.dto.http.CACertificateResponseDto or
io.mosip.registration.keymanager.dto.CACertificateResponseDto) and update any
references in the test accordingly so there is no collision between the two
classes.
- Around line 51-53: Remove the unused okhttp3 imports Headers, Protocol, and
Request from MasterDataServiceImplTest.java; keep only the used
okhttp3.ResponseBody import so tests compile with strict lint—locate the import
block containing okhttp3.Headers, okhttp3.Protocol, and okhttp3.Request and
delete those three entries.
🧹 Nitpick comments (3)
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PacketServiceImplTest.java (2)

404-445: Good update to match updateServerStatusWithTimestamp, but assert the timestamp semantics.

Switching the verification to updateServerStatusWithTimestamp(regId, "UPLOADED", anyLong()) (Line 439-443) aligns with the new repository API. Consider capturing the long and asserting it matches what the production code should be using (e.g., parsed server response time vs “now”), so the test verifies behavior rather than just “a timestamp was provided”.


950-1275: Nice coverage expansion; reduce time/file-system flakiness.

  • The new time-based tests (Line 950-1206) use System.currentTimeMillis(); these can get flaky if production logic uses different time sources/timezones. Prefer a fixed now (local variable) and derive all offsets from it, or inject a Clock in prod and use a fixed clock in tests.
  • The deletion tests (Line 1243-1260) create real temp files but don’t assert the file is actually deleted. If production deletes the file by path, add assertFalse(new File(filePath).exists()) after the call (and ensure cleanup on failure).
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/MasterDataServiceImplTest.java (1)

2424-4021: Good breadth of new tests; consider trimming private-method reflection and “expects NPE” cases.

The new block adds a lot of coverage (Line 2424-4021), but:

  • Many tests invoke private methods via ReflectionTestUtils—these tend to be brittle to refactors. Prefer exercising behavior through public APIs where feasible.
  • Several tests assert NullPointerException for error paths; that can lock in undesirable behavior (vs returning defaults or throwing domain exceptions). If NPE is intentional, consider asserting on message/type from a controlled exception instead.
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9507421 and 6c48ff9.

📒 Files selected for processing (7)
  • android/clientmanager/src/test/java/io/mosip/registration/clientmanager/config/AppModuleTest.java
  • android/clientmanager/src/test/java/io/mosip/registration/clientmanager/jobs/RegistrationDeletionJobTest.java
  • android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/Biometrics095ServiceTest.java
  • android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/JobManagerServiceImplTest.java
  • android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/LocalConfigServiceImplTest.java
  • android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/MasterDataServiceImplTest.java
  • android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PacketServiceImplTest.java
🔇 Additional comments (13)
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/Biometrics095ServiceTest.java (1)

74-76: LGTM! Explicit environment mocking improves test clarity.

The added mocks for SERVER_ACTIVE_PROFILE make the environment value explicit ("Developer") for capture request tests, improving test predictability and readability.

Also applies to: 175-176

android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/LocalConfigServiceImplTest.java (5)

67-78: LGTM! Proper delegation testing.

The test correctly verifies that getValue delegates to the DAO layer and returns the expected result.


80-90: LGTM! Comprehensive permission retrieval test.

The test validates that getPermittedJobs correctly delegates to the DAO with the appropriate constant (PERMITTED_JOB_TYPE).


92-153: LGTM! Thorough input validation coverage.

Excellent coverage of edge cases for modifyJob input validation:

  • Null, empty, and blank checks for both name and value parameters
  • Invalid cron expression validation
  • Proper verification that DAO is never called when validation fails

155-166: LGTM! Permission enforcement test.

The test correctly validates that unauthorized job modifications are rejected, ensuring security boundaries are enforced.


168-192: LGTM! Success path validation.

Both tests verify successful delegation to the DAO for valid inputs, including proper handling of whitespace in cron expressions.

android/clientmanager/src/test/java/io/mosip/registration/clientmanager/jobs/RegistrationDeletionJobTest.java (2)

48-58: LGTM! Exception handling test.

The test correctly verifies that when deleteRegistrationPackets throws an exception, triggerJob returns false and the exception is handled gracefully.


60-67: LGTM! Logging verification test.

The test validates that the deletion method is invoked during job execution.

android/clientmanager/src/test/java/io/mosip/registration/clientmanager/config/AppModuleTest.java (3)

109-113: LGTM! Mock additions for new dependencies.

The mock declarations for LocalConfigService and PacketService properly support the updated dependency injection wiring in the AppModule.


208-208: LGTM! Updated parameter list.

The test correctly passes the new packetService dependency to provideRegistrationService, aligning with the updated method signature.


251-251: LGTM! Updated parameter list.

The test correctly passes the new localConfigService dependency to provideJobManagerService, aligning with the updated method signature.

android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/JobManagerServiceImplTest.java (2)

20-20: LGTM! Proper mock setup for new dependency.

The import and mock declaration for LocalConfigService are correctly added to support the updated JobManagerServiceImpl constructor signature.

Also applies to: 46-47


63-63: LGTM! Consistent constructor updates across all tests.

All JobManagerServiceImpl instantiations have been systematically updated to include the new mockLocalConfigService parameter, ensuring test compatibility with the updated service signature.

Also applies to: 127-129, 146-146, 161-161, 176-176, 206-206, 236-236, 251-251, 257-257, 279-279, 294-294, 306-306, 323-323, 342-342, 356-356, 368-368, 380-380, 390-390, 398-398, 406-406, 415-415, 438-438, 461-461, 476-476, 491-491, 506-506, 517-517, 527-527, 536-536, 546-546, 557-557, 578-578, 591-591

Comment on lines +36 to +46
@Test
public void testTriggerJob_SuccessfulDeletion_ReturnsTrue() {
int jobId = 1;
long currentTimeMillis = System.currentTimeMillis();

boolean result = registrationDeletionJob.triggerJob(jobId);

assertTrue(result);
verify(packetService).deleteRegistrationPackets();
verify(registrationDeletionJob).logJobTransaction(jobId, TimeUnit.MILLISECONDS.toSeconds(currentTimeMillis));
}
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

Fix the timestamp verification logic.

The test captures currentTimeMillis at line 39 but then verifies logJobTransaction is called with TimeUnit.MILLISECONDS.toSeconds(currentTimeMillis) at line 45. However, the actual elapsed time calculation in the production code will differ from this pre-captured value, causing the verification to fail.

Consider either:

  1. Using any() matcher for the timestamp parameter if exact timing isn't critical
  2. Using argument captor to verify the timestamp is reasonable (e.g., within expected range)
  3. Mocking the time source if precise timing verification is required
🔧 Proposed fix
     @Test
     public void testTriggerJob_SuccessfulDeletion_ReturnsTrue() {
         int jobId = 1;
-        long currentTimeMillis = System.currentTimeMillis();

         boolean result = registrationDeletionJob.triggerJob(jobId);

         assertTrue(result);
         verify(packetService).deleteRegistrationPackets();
-        verify(registrationDeletionJob).logJobTransaction(jobId, TimeUnit.MILLISECONDS.toSeconds(currentTimeMillis));
+        verify(registrationDeletionJob).logJobTransaction(eq(jobId), anyLong());
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Test
public void testTriggerJob_SuccessfulDeletion_ReturnsTrue() {
int jobId = 1;
long currentTimeMillis = System.currentTimeMillis();
boolean result = registrationDeletionJob.triggerJob(jobId);
assertTrue(result);
verify(packetService).deleteRegistrationPackets();
verify(registrationDeletionJob).logJobTransaction(jobId, TimeUnit.MILLISECONDS.toSeconds(currentTimeMillis));
}
@Test
public void testTriggerJob_SuccessfulDeletion_ReturnsTrue() {
int jobId = 1;
boolean result = registrationDeletionJob.triggerJob(jobId);
assertTrue(result);
verify(packetService).deleteRegistrationPackets();
verify(registrationDeletionJob).logJobTransaction(eq(jobId), anyLong());
}
🤖 Prompt for AI Agents
In
@android/clientmanager/src/test/java/io/mosip/registration/clientmanager/jobs/RegistrationDeletionJobTest.java
around lines 36 - 46, The timestamp verification in
testTriggerJob_SuccessfulDeletion_ReturnsTrue is brittle because
currentTimeMillis is captured before triggerJob and the production code computes
elapsed time differently; update the test to avoid exact-match timing: replace
the strict verification of logJobTransaction(jobId,
TimeUnit.MILLISECONDS.toSeconds(currentTimeMillis)) with either
verify(registrationDeletionJob).logJobTransaction(eq(jobId), anyLong()) or use
an ArgumentCaptor<Long> to capture the timestamp and assert it falls within an
expected range, or alternatively mock the time source used by
registrationDeletionJob so you can assert an exact value; ensure
packetService.deleteRegistrationPackets() is still verified and keep references
to registrationDeletionJob.triggerJob and logJobTransaction in your changes.

Comment on lines +23 to 24
import io.mosip.registration.clientmanager.dto.http.CACertificateResponseDto;
import io.mosip.registration.keymanager.exception.KeymanagerServiceException;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid ambiguous CACertificateResponseDto imports (two classes with same name).

You import io.mosip.registration.keymanager.dto.* (Line 22) and also io.mosip.registration.clientmanager.dto.http.CACertificateResponseDto (Line 23-24). Since both packages contain a CACertificateResponseDto, this is easy to misuse and hard to read.

Recommendation: remove the wildcard import and explicitly import only what you use, or fully-qualify one of the types consistently.

🤖 Prompt for AI Agents
In
@android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/MasterDataServiceImplTest.java
around lines 23 - 24, In MasterDataServiceImplTest, remove the ambiguous
wildcard import io.mosip.registration.keymanager.dto.* and replace it with
explicit imports for only the types you actually use (or alternatively
fully-qualify one of the CACertificateResponseDto references); ensure you keep a
single, unambiguous import for CACertificateResponseDto (either
io.mosip.registration.clientmanager.dto.http.CACertificateResponseDto or
io.mosip.registration.keymanager.dto.CACertificateResponseDto) and update any
references in the test accordingly so there is no collision between the two
classes.

Comment on lines +51 to +53
import okhttp3.Headers;
import okhttp3.Protocol;
import okhttp3.Request;
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if file exists and read it to verify imports and usage
file_path="android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/MasterDataServiceImplTest.java"

if [ ! -f "$file_path" ]; then
    echo "File not found: $file_path"
    exit 1
fi

echo "=== Checking for okhttp3 imports ==="
rg "import okhttp3\.(Headers|Protocol|Request)" "$file_path" -n

echo ""
echo "=== Checking for usage of Headers, Protocol, Request classes ==="
# Search for actual usage (excluding import statements)
rg "\b(Headers|Protocol|Request)\b" "$file_path" -n | grep -v "^[0-9]*:\s*import"

echo ""
echo "=== Full file line count and structure ==="
wc -l "$file_path"
echo ""
echo "=== Lines around 51-53 ==="
sed -n '45,60p' "$file_path"

Repository: mosip/android-registration-client

Length of output: 875


Remove unused okhttp3 imports.

The imports okhttp3.Headers, okhttp3.Protocol, and okhttp3.Request (lines 51-53) are not used anywhere in this test file. These unused imports can cause build failures with strict lint settings. Only okhttp3.ResponseBody is used and should be retained.

🤖 Prompt for AI Agents
In
@android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/MasterDataServiceImplTest.java
around lines 51 - 53, Remove the unused okhttp3 imports Headers, Protocol, and
Request from MasterDataServiceImplTest.java; keep only the used
okhttp3.ResponseBody import so tests compile with strict lint—locate the import
block containing okhttp3.Headers, okhttp3.Protocol, and okhttp3.Request and
delete those three entries.

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: 3

Caution

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

⚠️ Outside diff range comments (3)
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PreCheckValidatorServiceImplTest.java (1)

456-472: ⚠️ Potential issue | 🟡 Minor

Test name and comment are misleading; this test duplicates testValidateSyncStatus_JobWithNullApiName_Skipped.

The test is named testValidateSyncStatus_JobWithNullId_Skipped and the comment says "Create job with null ID", but the implementation creates a SyncJobDef with a valid JOB_ID_1 and then sets apiName to null. This makes the test identical to testValidateSyncStatus_JobWithNullApiName_Skipped at lines 474-490.

If the intent was to test a job with a null ID, the new constructor SyncJobDef(String id) would need to accept null. Otherwise, consider removing this duplicate test or renaming/refactoring to test a distinct scenario.

android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PreRegZipHandlingServiceImplTest.java (1)

401-419: ⚠️ Potential issue | 🟡 Minor

Test lacks assertion for the expected exception.

The test name indicates it should verify an exception is thrown when entry count exceeds threshold, but there's no assertion or expected annotation. The test will pass regardless of whether the exception is thrown. Additionally, new byte[5] creates an invalid zip, not a zip with entries exceeding the threshold.

🐛 Proposed fix
     `@Test`
     public void test_throws_exception_when_entry_count_exceeds_threshold() throws Exception {
         ReflectionTestUtils.setField(service, "registrationService", mockRegistrationService);
         ReflectionTestUtils.setField(service, "applicantValidDocumentDao", mockApplicantValidDocumentDao);
         ReflectionTestUtils.setField(service, "THRESHOLD_ENTRIES", 2);
         ReflectionTestUtils.setField(service, "THRESHOLD_SIZE", 200000L);
         ReflectionTestUtils.setField(service, "THRESHOLD_RATIO", 10);

         Map<String, DocumentDto> documentsMap = new HashMap<>();
         Map<String, Object> demographicsMap = new HashMap<>();

         when(mockRegistrationService.getRegistrationDto()).thenReturn(regDto);
         when(regDto.getDocuments()).thenReturn(documentsMap);
         when(regDto.getDemographics()).thenReturn(demographicsMap);

-        byte[] zipFile = new byte[5];
-
-        service.extractPreRegZipFile(zipFile);
+        // Create a zip file with more entries than the threshold
+        byte[] zipFile = createZipFileWithEntries(5, 100); // 5 entries > threshold of 2
+
+        assertThrows(RegBaseUncheckedException.class, () -> {
+            service.extractPreRegZipFile(zipFile);
+        });
     }
android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java (1)

3-40: ⚠️ Potential issue | 🟡 Minor

Fix duplicate mockito-inline version declarations in android/packetmanager/build.gradle.

The test file properly uses MockedStatic, and mockito-inline is present as a test dependency. However, mockito-inline is declared twice with conflicting versions (4.11.0 at line 63 and 5.0.0 at line 92). Remove the older 4.11.0 declaration to avoid build ambiguity. Additionally, verify that mockito-core:5.1.1 and mockito-inline:5.0.0 are compatible (minor version mismatch between core and inline).

🤖 Fix all issues with AI agents
In
`@android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/RegistrationServiceImpl.java`:
- Around line 317-321: In RegistrationServiceImpl, the null/empty check for
containerPath is wrong and can NPE; change the condition in the block that sets
registrationDto.packetId to ensure containerPath is non-null AND non-empty (use
&& instead of ||), or preferably use a safe utility like
StringUtils.isNotBlank(containerPath) (or containerPath != null &&
!containerPath.trim().isEmpty()) before calling substring/trim; then compute
packetId from containerPath, strip ".zip", and call
this.registrationDto.setPacketId(packetId).

In
`@android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PreRegZipHandlingServiceImplTest.java`:
- Around line 367-374: The test contains duplicated verify calls for
mockRegistrationDto.addWithoutDocument(...),
mockRegistrationDto.getDemographics(), and
mockIdentitySchemaRepository.getAllFieldSpec(...); remove the repeated block so
each verification appears only once in PreRegZipHandlingServiceImplTest (look
for the verify calls referencing mockRegistrationDto and
mockIdentitySchemaRepository and remove the second identical group), leaving a
single set of verifies for addWithoutDocument, getDemographics, and
getAllFieldSpec.

In
`@android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java`:
- Around line 1623-1626: The tests set global Robolectric shadow state via
ShadowEnvironment.setExternalStorageState(...) but never restore it, causing
cross-test leakage; update the two tests (the ones that call
ShadowEnvironment.setExternalStorageState() at the shown diffs) to capture the
prior state(s) (call ShadowEnvironment.getExternalStorageState() and
ShadowEnvironment.getExternalStorageState(baseDir) as applicable) before
changing them and restore those values in a finally block (or restore them in
the existing tearDown() method) by calling
ShadowEnvironment.setExternalStorageState(...) with the saved values so the
global shadow state is always reset after each test.
🧹 Nitpick comments (10)
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PreCheckValidatorServiceImplTest.java (1)

42-42: Consider documenting the rationale for using MockitoJUnitRunner.Silent.

The Silent runner suppresses warnings about unnecessary stubbings. While this reduces test noise, it can also mask tests that have stale or unused mock configurations. If specific tests require unused stubs for readability/setup consistency, consider using @MockitoSettings(strictness = Strictness.LENIENT) on individual tests instead for finer control.

android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/RegistrationServiceImpl.java (1)

252-253: Address commented-out try-finally block or remove the comments.

The commented-out try and finally blocks suggest incomplete refactoring. If the try-finally is no longer needed, remove the comments entirely to avoid confusion. If it's intentionally deferred, consider adding a TODO with context.

Also applies to: 372-374

android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/RegistrationServiceImplTest.java (2)

126-129: Consider cleaning up the temporary directory after tests.

The temporary packets directory is created but never cleaned up. While this may not cause immediate issues, it could leave test artifacts on the filesystem. Consider adding cleanup in tearDown().

♻️ Proposed cleanup in tearDown
 `@After`
 public void tearDown() {
     if (storageUtilsMock != null) {
         storageUtilsMock.close();
     }
+    // Clean up temp directory
+    File packetDir = new File(System.getProperty("java.io.tmpdir"), "packets");
+    if (packetDir.exists()) {
+        packetDir.delete();
+    }
 }

75-75: Note: MockitoJUnitRunner.Silent suppresses unnecessary stubbing warnings.

Using Silent.class suppresses warnings for unused stubs. While this is acceptable for reducing noise in tests with lenient setup, be aware it may also hide legitimate stubbing issues. Ensure stubs are intentionally lenient where needed.

android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PreRegZipHandlingServiceImplTest.java (5)

308-317: Use try-with-resources for MockedStatic to prevent resource leaks.

If an assertion or other statement throws before .close() is called, the static mock will leak and potentially affect subsequent tests. This pattern is repeated in test_initPreRegAdapter_externalStorageNotMounted and test_initPreRegAdapter_externalStorageMounted.

♻️ Suggested refactor using try-with-resources
     `@Test`
     public void test_init_prereg_adapter_when_external_storage_not_mounted() {
-        MockedStatic<Environment> mockedEnvironment = Mockito.mockStatic(Environment.class);
-        mockedEnvironment.when(Environment::getExternalStorageState).thenReturn("unmounted");
-
-        ReflectionTestUtils.invokeMethod(service, "initPreRegAdapter", mockContext);
-
-        assertEquals(mockContext, ReflectionTestUtils.getField(service, "appContext"));
-
-        mockedEnvironment.close();
+        try (MockedStatic<Environment> mockedEnvironment = Mockito.mockStatic(Environment.class)) {
+            mockedEnvironment.when(Environment::getExternalStorageState).thenReturn("unmounted");
+
+            ReflectionTestUtils.invokeMethod(service, "initPreRegAdapter", mockContext);
+
+            assertEquals(mockContext, ReflectionTestUtils.getField(service, "appContext"));
+        }
     }

780-785: Clarify test intent and add proper assertion.

The empty catch block with comment "Should not throw, just print error" doesn't verify the expected behavior. If the method is expected to handle the error gracefully, explicitly assert what should happen (e.g., verify error logging, return value, or state).

♻️ Suggested improvement
         try {
             service.storePreRegPacketToDisk("id", new byte[] { 1, 2, 3 }, new CenterMachineDto());
+            // If we reach here, verify expected fallback behavior
+            // e.g., verify logging occurred or return value is as expected
         } catch (Exception e) {
-            // Should not throw, just print error
+            fail("Expected method to handle error gracefully without throwing: " + e.getMessage());
         }

981-1018: Consider addressing non-deterministic test behavior.

The comments acknowledge that test behavior depends on HashMap iteration order, which is non-deterministic. This could lead to flaky tests. Consider using a LinkedHashMap in the production code (if appropriate) or restructuring the test to be deterministic.


717-723: Apply try-with-resources pattern here as well.

Same issue as noted earlier - MockedStatic should use try-with-resources to ensure cleanup.

♻️ Suggested refactor
     `@Test`
     public void test_initPreRegAdapter_externalStorageNotMounted() {
-        MockedStatic<Environment> mockedEnv = Mockito.mockStatic(Environment.class);
-        mockedEnv.when(Environment::getExternalStorageState).thenReturn("unmounted");
-        ReflectionTestUtils.invokeMethod(service, "initPreRegAdapter", mockContext);
-        assertEquals(mockContext, ReflectionTestUtils.getField(service, "appContext"));
-        mockedEnv.close();
+        try (MockedStatic<Environment> mockedEnv = Mockito.mockStatic(Environment.class)) {
+            mockedEnv.when(Environment::getExternalStorageState).thenReturn("unmounted");
+            ReflectionTestUtils.invokeMethod(service, "initPreRegAdapter", mockContext);
+            assertEquals(mockContext, ReflectionTestUtils.getField(service, "appContext"));
+        }
     }

962-968: Apply try-with-resources pattern here as well.

Same issue as noted earlier - MockedStatic should use try-with-resources to ensure cleanup.

♻️ Suggested refactor
     `@Test`
     public void test_initPreRegAdapter_externalStorageMounted() {
-        MockedStatic<Environment> mockedEnv = Mockito.mockStatic(Environment.class);
-        mockedEnv.when(Environment::getExternalStorageState).thenReturn(Environment.MEDIA_MOUNTED);
-        ReflectionTestUtils.invokeMethod(service, "initPreRegAdapter", mockContext);
-        assertEquals(mockContext, ReflectionTestUtils.getField(service, "appContext"));
-        mockedEnv.close();
+        try (MockedStatic<Environment> mockedEnv = Mockito.mockStatic(Environment.class)) {
+            mockedEnv.when(Environment::getExternalStorageState).thenReturn(Environment.MEDIA_MOUNTED);
+            ReflectionTestUtils.invokeMethod(service, "initPreRegAdapter", mockContext);
+            assertEquals(mockContext, ReflectionTestUtils.getField(service, "appContext"));
+        }
     }
android/clientmanager/src/test/java/io/mosip/registration/clientmanager/util/UserInterfaceHelperServiceTest.java (1)

28-28: Consider switching to MockitoJUnitRunner.StrictStubs.

The Silent mode suppresses stubbing warnings and doesn't detect unused stubs (visible in this file as the unused @Mock fields mockMissingImage and mockResultBitmap). StrictStubs will help keep tests clean by catching unused stubbings and argument mismatches, which improves debugging.

Suggested change
-@RunWith(MockitoJUnitRunner.Silent.class)
+@RunWith(MockitoJUnitRunner.StrictStubs.class)

Comment on lines 317 to 321
if (containerPath != null || !containerPath.trim().isEmpty()) {
String packetId = containerPath.substring(containerPath.lastIndexOf("/") + 1);
packetId = packetId.replace(".zip", "");
this.registrationDto.setPacketId(packetId);
packetId = packetId.replace(".zip", "");
this.registrationDto.setPacketId(packetId);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical bug: NPE risk and incorrect condition logic.

The condition containerPath != null || !containerPath.trim().isEmpty() is logically flawed:

  1. If containerPath is null, the first part is false, so the second part is evaluated, causing a NullPointerException on .trim().
  2. The || operator means the block executes if either condition is true, but if containerPath is not null, it will always enter regardless of being empty.

The intended logic should use && to ensure containerPath is both non-null AND non-empty.

🐛 Proposed fix
-        if (containerPath != null || !containerPath.trim().isEmpty()) {
+        if (containerPath != null && !containerPath.trim().isEmpty()) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (containerPath != null || !containerPath.trim().isEmpty()) {
String packetId = containerPath.substring(containerPath.lastIndexOf("/") + 1);
packetId = packetId.replace(".zip", "");
this.registrationDto.setPacketId(packetId);
packetId = packetId.replace(".zip", "");
this.registrationDto.setPacketId(packetId);
}
if (containerPath != null && !containerPath.trim().isEmpty()) {
String packetId = containerPath.substring(containerPath.lastIndexOf("/") + 1);
packetId = packetId.replace(".zip", "");
this.registrationDto.setPacketId(packetId);
}
🤖 Prompt for AI Agents
In
`@android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/RegistrationServiceImpl.java`
around lines 317 - 321, In RegistrationServiceImpl, the null/empty check for
containerPath is wrong and can NPE; change the condition in the block that sets
registrationDto.packetId to ensure containerPath is non-null AND non-empty (use
&& instead of ||), or preferably use a safe utility like
StringUtils.isNotBlank(containerPath) (or containerPath != null &&
!containerPath.trim().isEmpty()) before calling substring/trim; then compute
packetId from containerPath, strip ".zip", and call
this.registrationDto.setPacketId(packetId).

Comment on lines +367 to 374
verify(mockRegistrationDto, never()).addWithoutDocument(anyString(), anyString(), anyString(), anyString(),
anyString());
verify(mockRegistrationDto, never()).getDemographics();
verify(mockIdentitySchemaRepository, never()).getAllFieldSpec(any(Context.class), anyDouble());
verify(mockRegistrationDto, never()).addWithoutDocument(anyString(), anyString(), anyString(), anyString(), anyString());
verify(mockRegistrationDto, never()).addWithoutDocument(anyString(), anyString(), anyString(), anyString(),
anyString());
verify(mockRegistrationDto, never()).getDemographics();
verify(mockIdentitySchemaRepository, never()).getAllFieldSpec(any(Context.class), anyDouble());
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

Remove duplicate verification calls.

Lines 371-374 are exact duplicates of lines 367-370. This appears to be a copy-paste error and should be removed.

🐛 Proposed fix
         verify(mockRegistrationDto, never()).addWithoutDocument(anyString(), anyString(), anyString(), anyString(),
                 anyString());
         verify(mockRegistrationDto, never()).getDemographics();
         verify(mockIdentitySchemaRepository, never()).getAllFieldSpec(any(Context.class), anyDouble());
-        verify(mockRegistrationDto, never()).addWithoutDocument(anyString(), anyString(), anyString(), anyString(),
-                anyString());
-        verify(mockRegistrationDto, never()).getDemographics();
-        verify(mockIdentitySchemaRepository, never()).getAllFieldSpec(any(Context.class), anyDouble());
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
verify(mockRegistrationDto, never()).addWithoutDocument(anyString(), anyString(), anyString(), anyString(),
anyString());
verify(mockRegistrationDto, never()).getDemographics();
verify(mockIdentitySchemaRepository, never()).getAllFieldSpec(any(Context.class), anyDouble());
verify(mockRegistrationDto, never()).addWithoutDocument(anyString(), anyString(), anyString(), anyString(), anyString());
verify(mockRegistrationDto, never()).addWithoutDocument(anyString(), anyString(), anyString(), anyString(),
anyString());
verify(mockRegistrationDto, never()).getDemographics();
verify(mockIdentitySchemaRepository, never()).getAllFieldSpec(any(Context.class), anyDouble());
verify(mockRegistrationDto, never()).addWithoutDocument(anyString(), anyString(), anyString(), anyString(),
anyString());
verify(mockRegistrationDto, never()).getDemographics();
verify(mockIdentitySchemaRepository, never()).getAllFieldSpec(any(Context.class), anyDouble());
🤖 Prompt for AI Agents
In
`@android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PreRegZipHandlingServiceImplTest.java`
around lines 367 - 374, The test contains duplicated verify calls for
mockRegistrationDto.addWithoutDocument(...),
mockRegistrationDto.getDemographics(), and
mockIdentitySchemaRepository.getAllFieldSpec(...); remove the repeated block so
each verification appears only once in PreRegZipHandlingServiceImplTest (look
for the verify calls referencing mockRegistrationDto and
mockIdentitySchemaRepository and remove the second identical group), leaving a
single set of verifies for addWithoutDocument, getDemographics, and
getAllFieldSpec.

Comment on lines +1623 to 1626
// Set external storage to mounted for baseDir so getExternalStorageState(baseDir) returns MEDIA_MOUNTED
ShadowEnvironment.setExternalStorageState(Environment.MEDIA_MOUNTED);
ShadowEnvironment.setExternalStorageState(baseDir, Environment.MEDIA_MOUNTED);

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

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and examine the test file
find . -type f -name "PosixAdapterServiceImplTest.java" 2>/dev/null

Repository: mosip/android-registration-client

Length of output: 191


🏁 Script executed:

# Read the test file around the specified lines with context
if [ -f "android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java" ]; then
  echo "=== Lines 1610-1660 (context around 1623-1626 and 1648-1651) ==="
  sed -n '1610,1660p' "android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java" | cat -n
fi

Repository: mosip/android-registration-client

Length of output: 3142


🏁 Script executed:

# Get full test method bodies and check for cleanup
sed -n '1620,1670p' "android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java" | cat -n

Repository: mosip/android-registration-client

Length of output: 3254


🏁 Script executed:

# Search for `@After`, tearDown, and cleanup methods in the test class
grep -n "@After\|tearDown\|ShadowEnvironment" "android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java" | head -30

Repository: mosip/android-registration-client

Length of output: 525


🏁 Script executed:

# Read the tearDown method
sed -n '87,110p' "android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java" | cat -n

Repository: mosip/android-registration-client

Length of output: 915


🏁 Script executed:

# Also search for any other ShadowEnvironment resets in the tearDown or elsewhere
sed -n '87,150p' "android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java" | cat -n

Repository: mosip/android-registration-client

Length of output: 3051


🏁 Script executed:

# Search for other tests that use getExternalStorageState or depend on storage state
grep -n "getExternalStorageState\|Environment\\.MEDIA" "android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java"

Repository: mosip/android-registration-client

Length of output: 744


🏁 Script executed:

# Get a count of total test methods to understand scope
grep -c "@Test" "android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java"

Repository: mosip/android-registration-client

Length of output: 79


🏁 Script executed:

# Check the test around line 1450 that patches getExternalStorageState
sed -n '1440,1470p' "android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java" | cat -n

Repository: mosip/android-registration-client

Length of output: 1731


🏁 Script executed:

# Check if there are tests that run AFTER the two problematic tests and might be affected
# Get the line numbers and test method names for context
grep -n "@Test" "android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java" | tail -10

Repository: mosip/android-registration-client

Length of output: 226


🏁 Script executed:

# Check if there are any ShadowEnvironment reset/cleanup patterns elsewhere
grep -rn "reset\|Reset\|clearProperty" "android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java" | head -10

Repository: mosip/android-registration-client

Length of output: 205


Add cleanup for ShadowEnvironment state to prevent cross-test leakage.

ShadowEnvironment.setExternalStorageState() maintains global Robolectric shadow state that persists across tests. The current tearDown() method only cleans up file resources but does not restore the external storage state, causing tests running after these methods to inherit the MEDIA_MOUNTED state. Use a try-finally block to restore the original state in both test methods:

Suggested pattern (apply to both tests)
-        ShadowEnvironment.setExternalStorageState(Environment.MEDIA_MOUNTED);
-        ShadowEnvironment.setExternalStorageState(baseDir, Environment.MEDIA_MOUNTED);
+        String originalState = Environment.getExternalStorageState();
+        try {
+            ShadowEnvironment.setExternalStorageState(Environment.MEDIA_MOUNTED);
+            ShadowEnvironment.setExternalStorageState(baseDir, Environment.MEDIA_MOUNTED);
+            // ...
+        } finally {
+            ShadowEnvironment.setExternalStorageState(originalState);
+            ShadowEnvironment.setExternalStorageState(baseDir, originalState);
+        }

Also applies to: 1648-1651

🤖 Prompt for AI Agents
In
`@android/packetmanager/src/test/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImplTest.java`
around lines 1623 - 1626, The tests set global Robolectric shadow state via
ShadowEnvironment.setExternalStorageState(...) but never restore it, causing
cross-test leakage; update the two tests (the ones that call
ShadowEnvironment.setExternalStorageState() at the shown diffs) to capture the
prior state(s) (call ShadowEnvironment.getExternalStorageState() and
ShadowEnvironment.getExternalStorageState(baseDir) as applicable) before
changing them and restore those values in a finally block (or restore them in
the existing tearDown() method) by calling
ShadowEnvironment.setExternalStorageState(...) with the saved values so the
global shadow state is always reset after each test.

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.

1 participant