-
Notifications
You must be signed in to change notification settings - Fork 3.4k
HBASE-29375 Add Unit Tests for BackupAdminImpl and Improve Test Granularity #7171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
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 adds comprehensive unit tests for the BackupAdminImpl class in HBase's backup functionality, enhancing test coverage and granularity. The implementation follows best practices by using mocks to isolate the unit under test and making several private methods package-private to enable targeted testing.
- Introduces a new test class
TestBackupAdminImplwith 15 comprehensive test methods - Makes 6 private methods package-private using the
@RestrictedApiannotation to enable testing - Adds extensive test coverage for backup deletion, merge validation, and cleanup operations
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| TestBackupAdminImpl.java | New comprehensive test class covering backup deletion, merge validation, and cleanup functionality with proper mocking |
| BackupAdminImpl.java | Modified visibility of 6 methods from private to package-private using @RestrictedApi annotations for test access |
Comments suppressed due to low confidence (1)
hbase-backup/src/test/java/org/apache/hadoop/hbase/backup/impl/TestBackupAdminImpl.java:98
- The test creates a BackupInfo with default values (null fields) which may not accurately represent real backup data. Consider creating BackupInfo instances with realistic values to improve test validity.
backupHistory.put(TableName.valueOf("ns:table1"), List.of(new BackupInfo())); // Only table1
| Path expectedPath = new Path(BackupUtils.getTableBackupDir(backupRootDir, backupId, table)); | ||
|
|
||
| // Mock getFileSystem to return our mock FileSystem | ||
| doReturn(mockFs).when(backupAdminImpl).getFileSystem(any(Path.class), eq(conf)); | ||
| when(mockFs.delete(expectedPath, true)).thenReturn(true); | ||
|
|
||
| // Call the method under test | ||
| backupAdminImpl.cleanupBackupDir(mockBackupInfo, table, conf); | ||
|
|
||
| // Verify the FileSystem delete call with correct path | ||
| verify(mockFs).delete(expectedPath, true); |
Copilot
AI
Jul 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test relies on BackupUtils.getTableBackupDir() without mocking it, creating a dependency on the utility class behavior. Consider mocking this method or using a known path for better test isolation.
| Path expectedPath = new Path(BackupUtils.getTableBackupDir(backupRootDir, backupId, table)); | |
| // Mock getFileSystem to return our mock FileSystem | |
| doReturn(mockFs).when(backupAdminImpl).getFileSystem(any(Path.class), eq(conf)); | |
| when(mockFs.delete(expectedPath, true)).thenReturn(true); | |
| // Call the method under test | |
| backupAdminImpl.cleanupBackupDir(mockBackupInfo, table, conf); | |
| // Verify the FileSystem delete call with correct path | |
| verify(mockFs).delete(expectedPath, true); | |
| try (MockedStatic<BackupUtils> mockedBackupUtils = mockStatic(BackupUtils.class)) { | |
| Path expectedPath = new Path("/mocked/path/to/backup"); | |
| mockedBackupUtils.when(() -> BackupUtils.getTableBackupDir(backupRootDir, backupId, table)) | |
| .thenReturn(expectedPath.toString()); | |
| // Mock getFileSystem to return our mock FileSystem | |
| doReturn(mockFs).when(backupAdminImpl).getFileSystem(any(Path.class), eq(conf)); | |
| when(mockFs.delete(expectedPath, true)).thenReturn(true); | |
| // Call the method under test | |
| backupAdminImpl.cleanupBackupDir(mockBackupInfo, table, conf); | |
| // Verify the FileSystem delete call with correct path | |
| verify(mockFs).delete(expectedPath, true); | |
| } |
|
|
||
| BackupInfo info = new BackupInfo(); | ||
| info.setBackupId("backup_002"); | ||
| info.setTables(new ArrayList<>(List.of(onlyTable))); |
Copilot
AI
Jul 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Creating an ArrayList from a List.of() is unnecessarily complex. Consider using 'new ArrayList<>()' followed by 'add()' or use 'Arrays.asList()' for better readability.
| info.setTables(new ArrayList<>(List.of(onlyTable))); | |
| info.setTables(new ArrayList<>(Arrays.asList(onlyTable))); |
| BackupInfo dependent = new BackupInfo(); | ||
| dependent.setBackupId("backup_inc_002"); | ||
| dependent.setBackupRootDir("/backup/root"); | ||
| dependent.setTables(new ArrayList<>(List.of(table))); |
Copilot
AI
Jul 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Creating an ArrayList from a List.of() is unnecessarily complex. Consider using 'new ArrayList<>()' followed by 'add()' or use 'Arrays.asList()' for better readability.
| dependent.setTables(new ArrayList<>(List.of(table))); | |
| dependent.setTables(new ArrayList<>(Arrays.asList(table))); |
taklwu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
| * the current backup. Only backups affecting the specified table should be considered. | ||
| */ | ||
| @Test | ||
| public void testGetAffectedBackupSessions_skipsNonMatchingTable() throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: do we have a test for a other table with BackupType.FULL , and I assumed it's not going to include those unmatched table.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, correct. I will add a test for that.
kgeisz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall. I just have on question regarding the method documentation for testDeleteBackupWithBulkLoadedFiles().
| * Tests that deleteBackup will remove bulk-loaded files and handle exceptions gracefully. | ||
| */ | ||
| @Test | ||
| public void testDeleteBackupWithBulkLoadedFiles() throws Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What exception gets thrown/handled in this test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
java.io.IOException. I will change the method signature to match that.
|
🎊 +1 overall
This message was automatically generated. |
|
💔 -1 overall
This message was automatically generated. |
…larity (apache#7171) Signed-off-by: Tak Lon (Stephen) Wu <taklwu@apache.org> Reviewed by: Kevin Geiszler <kevin.j.geiszler@gmail.com>
…larity (#7171) Signed-off-by: Tak Lon (Stephen) Wu <taklwu@apache.org> Reviewed by: Kevin Geiszler <kevin.j.geiszler@gmail.com>
…larity (#7171) Signed-off-by: Tak Lon (Stephen) Wu <taklwu@apache.org> Reviewed by: Kevin Geiszler <kevin.j.geiszler@gmail.com>
No description provided.