Skip to content

Commit 12ff7ad

Browse files
committed
test: add unit tests for cleanupProject method in PR 14150
Add comprehensive unit tests for the cleanupProject method to verify: - Account-level project mappings are removed when project is deleted - User-level project mappings are removed when project is deleted - Multiple accounts and users are properly unassigned - Proper error handling when account deletion fails - Proper error handling when unassigning accounts fails - Correct behavior when no accounts/users exist Tests verify that the method correctly calls unassignAccountFromProject for each project mapping and properly cleans up invitations.
1 parent 4fa848c commit 12ff7ad

1 file changed

Lines changed: 213 additions & 0 deletions

File tree

‎server/src/test/java/com/cloud/projects/ProjectManagerImplTest.java‎

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,17 @@
3636
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
3737

3838
import com.cloud.projects.dao.ProjectDao;
39+
import com.cloud.projects.dao.ProjectInvitationDao;
40+
import com.cloud.resourcelimit.CheckedReservation;
41+
import com.cloud.user.Account;
42+
import com.cloud.user.AccountManager;
43+
import com.cloud.user.AccountVO;
44+
import com.cloud.user.ResourceLimitService;
45+
import com.cloud.user.User;
46+
import com.cloud.user.dao.AccountDao;
3947
import com.cloud.utils.component.ComponentContext;
48+
import com.cloud.utils.db.Transaction;
49+
import com.cloud.utils.db.TransactionCallback;
4050

4151

4252
@RunWith(MockitoJUnitRunner.class)
@@ -49,6 +59,24 @@ public class ProjectManagerImplTest {
4959
@Mock
5060
ProjectDao projectDao;
5161

62+
@Mock
63+
ProjectInvitationDao projectInvitationDao;
64+
65+
@Mock
66+
ProjectAccountDao projectAccountDao;
67+
68+
@Mock
69+
AccountDao accountDao;
70+
71+
@Mock
72+
ResourceLimitService resourceLimitMgr;
73+
74+
@Mock
75+
ReservationDao reservationDao;
76+
77+
@Mock
78+
AccountManager accountManager;
79+
5280
List<ProjectVO> updateProjects;
5381

5482
@Before
@@ -317,6 +345,182 @@ public void unassignAccountFromProjectTestWithAdminRole() {
317345
Mockito.verify(projectAccountDao).remove(2L);
318346
}
319347

348+
@Test
349+
public void cleanupProjectTestWithAccountAddedToProject() throws Exception {
350+
ProjectVO project = mockProject(100L, 1L);
351+
AccountVO projectAccount = mockAccount(1L);
352+
AccountVO callerAccount = mockAccount(2L);
353+
ProjectAccountVO addedAccount = mockProjectAccountWithIds(10L, 100L, 10L, Role.Regular);
354+
355+
Mockito.when(accountDao.findById(1L)).thenReturn(projectAccount);
356+
Mockito.doReturn(true).when(projectManager).unassignAccountFromProject(100L, 10L);
357+
Mockito.when(projectAccountDao.listByProjectId(100L))
358+
.thenReturn(List.of(addedAccount));
359+
Mockito.when(accountManager.deleteAccount(projectAccount, 1L, callerAccount)).thenReturn(true);
360+
361+
try (MockedStatic<Transaction> mockedTransaction = Mockito.mockStatic(Transaction.class)) {
362+
mockedTransaction.when(() -> Transaction.execute(Mockito.any(TransactionCallback.class)))
363+
.thenAnswer(invocation -> {
364+
TransactionCallback<?> callback = invocation.getArgument(0);
365+
return callback.doInTransaction(null);
366+
});
367+
368+
boolean result = invokeCleanupProject(project, callerAccount, 1L);
369+
370+
Assert.assertTrue(result);
371+
Mockito.verify(accountManager).deleteAccount(projectAccount, 1L, callerAccount);
372+
Mockito.verify(projectAccountDao).listByProjectId(100L);
373+
Mockito.verify(projectInvitationDao).cleanupInvitations(100L);
374+
}
375+
}
376+
377+
@Test
378+
public void cleanupProjectTestWithUserAddedToProject() throws Exception {
379+
ProjectVO project = mockProject(100L, 1L);
380+
AccountVO projectAccount = mockAccount(1L);
381+
AccountVO callerAccount = mockAccount(2L);
382+
ProjectAccountVO userMapping = mockProjectAccountWithIds(11L, 100L, 20L, Role.Admin);
383+
384+
Mockito.when(accountDao.findById(1L)).thenReturn(projectAccount);
385+
Mockito.doReturn(true).when(projectManager).unassignAccountFromProject(100L, 20L);
386+
Mockito.when(projectAccountDao.listByProjectId(100L))
387+
.thenReturn(List.of(userMapping));
388+
Mockito.when(accountManager.deleteAccount(projectAccount, 1L, callerAccount)).thenReturn(true);
389+
390+
try (MockedStatic<Transaction> mockedTransaction = Mockito.mockStatic(Transaction.class)) {
391+
mockedTransaction.when(() -> Transaction.execute(Mockito.any(TransactionCallback.class)))
392+
.thenAnswer(invocation -> {
393+
TransactionCallback<?> callback = invocation.getArgument(0);
394+
return callback.doInTransaction(null);
395+
});
396+
397+
boolean result = invokeCleanupProject(project, callerAccount, 1L);
398+
399+
Assert.assertTrue(result);
400+
Mockito.verify(accountManager).deleteAccount(projectAccount, 1L, callerAccount);
401+
Mockito.verify(projectAccountDao).listByProjectId(100L);
402+
Mockito.verify(projectInvitationDao).cleanupInvitations(100L);
403+
}
404+
}
405+
406+
@Test
407+
public void cleanupProjectTestWithMultipleAccountsAndUsersRemoved() throws Exception {
408+
ProjectVO project = mockProject(100L, 1L);
409+
AccountVO projectAccount = mockAccount(1L);
410+
AccountVO callerAccount = mockAccount(2L);
411+
ProjectAccountVO account1 = mockProjectAccountWithIds(10L, 100L, 10L, Role.Regular);
412+
ProjectAccountVO user1 = mockProjectAccountWithIds(11L, 100L, 20L, Role.Admin);
413+
414+
Mockito.when(accountDao.findById(1L)).thenReturn(projectAccount);
415+
Mockito.doReturn(true).when(projectManager).unassignAccountFromProject(100L, 10L);
416+
Mockito.doReturn(true).when(projectManager).unassignAccountFromProject(100L, 20L);
417+
Mockito.when(projectAccountDao.listByProjectId(100L))
418+
.thenReturn(List.of(account1, user1));
419+
Mockito.when(accountManager.deleteAccount(projectAccount, 1L, callerAccount)).thenReturn(true);
420+
421+
try (MockedStatic<Transaction> mockedTransaction = Mockito.mockStatic(Transaction.class)) {
422+
mockedTransaction.when(() -> Transaction.execute(Mockito.any(TransactionCallback.class)))
423+
.thenAnswer(invocation -> {
424+
TransactionCallback<?> callback = invocation.getArgument(0);
425+
return callback.doInTransaction(null);
426+
});
427+
428+
boolean result = invokeCleanupProject(project, callerAccount, 1L);
429+
430+
Assert.assertTrue(result);
431+
Mockito.verify(accountManager).deleteAccount(projectAccount, 1L, callerAccount);
432+
Mockito.verify(projectAccountDao).listByProjectId(100L);
433+
Mockito.verify(projectInvitationDao).cleanupInvitations(100L);
434+
Mockito.verify(projectManager).unassignAccountFromProject(100L, 10L);
435+
Mockito.verify(projectManager).unassignAccountFromProject(100L, 20L);
436+
}
437+
}
438+
439+
@Test
440+
public void cleanupProjectTestAccountDeletionFailure() throws Exception {
441+
ProjectVO project = mockProject(100L, 1L);
442+
AccountVO projectAccount = mockAccount(1L);
443+
AccountVO callerAccount = mockAccount(2L);
444+
445+
Mockito.when(accountDao.findById(1L)).thenReturn(projectAccount);
446+
Mockito.when(accountManager.deleteAccount(projectAccount, 1L, callerAccount)).thenReturn(false);
447+
448+
boolean result = invokeCleanupProject(project, callerAccount, 1L);
449+
450+
Assert.assertFalse(result);
451+
Mockito.verify(accountManager).deleteAccount(projectAccount, 1L, callerAccount);
452+
Mockito.verify(projectAccountDao, Mockito.never()).listByProjectId(Mockito.anyLong());
453+
Mockito.verify(projectInvitationDao, Mockito.never()).cleanupInvitations(Mockito.anyLong());
454+
}
455+
456+
@Test
457+
public void cleanupProjectTestUnassignAccountFailure() throws Exception {
458+
ProjectVO project = mockProject(100L, 1L);
459+
AccountVO projectAccount = mockAccount(1L);
460+
AccountVO callerAccount = mockAccount(2L);
461+
ProjectAccountVO addedAccount = mockProjectAccountWithIds(10L, 100L, 10L, Role.Regular);
462+
463+
Mockito.when(accountDao.findById(1L)).thenReturn(projectAccount);
464+
Mockito.doReturn(false).when(projectManager).unassignAccountFromProject(100L, 10L);
465+
Mockito.when(projectAccountDao.listByProjectId(100L))
466+
.thenReturn(List.of(addedAccount));
467+
Mockito.when(accountManager.deleteAccount(projectAccount, 1L, callerAccount)).thenReturn(true);
468+
469+
try (MockedStatic<Transaction> mockedTransaction = Mockito.mockStatic(Transaction.class)) {
470+
mockedTransaction.when(() -> Transaction.execute(Mockito.any(TransactionCallback.class)))
471+
.thenAnswer(invocation -> {
472+
TransactionCallback<?> callback = invocation.getArgument(0);
473+
return callback.doInTransaction(null);
474+
});
475+
476+
boolean result = invokeCleanupProject(project, callerAccount, 1L);
477+
478+
Assert.assertFalse(result);
479+
Mockito.verify(projectManager).unassignAccountFromProject(100L, 10L);
480+
Mockito.verify(projectInvitationDao).cleanupInvitations(100L);
481+
}
482+
}
483+
484+
@Test
485+
public void cleanupProjectTestNoAccountsOrUsersToRemove() throws Exception {
486+
ProjectVO project = mockProject(100L, 1L);
487+
AccountVO projectAccount = mockAccount(1L);
488+
AccountVO callerAccount = mockAccount(2L);
489+
490+
Mockito.when(accountDao.findById(1L)).thenReturn(projectAccount);
491+
Mockito.when(projectAccountDao.listByProjectId(100L))
492+
.thenReturn(Collections.emptyList());
493+
Mockito.when(accountManager.deleteAccount(projectAccount, 1L, callerAccount)).thenReturn(true);
494+
495+
try (MockedStatic<Transaction> mockedTransaction = Mockito.mockStatic(Transaction.class)) {
496+
mockedTransaction.when(() -> Transaction.execute(Mockito.any(TransactionCallback.class)))
497+
.thenAnswer(invocation -> {
498+
TransactionCallback<?> callback = invocation.getArgument(0);
499+
return callback.doInTransaction(null);
500+
});
501+
502+
boolean result = invokeCleanupProject(project, callerAccount, 1L);
503+
504+
Assert.assertTrue(result);
505+
Mockito.verify(accountManager).deleteAccount(projectAccount, 1L, callerAccount);
506+
Mockito.verify(projectAccountDao).listByProjectId(100L);
507+
Mockito.verify(projectInvitationDao).cleanupInvitations(100L);
508+
}
509+
}
510+
511+
private boolean invokeCleanupProject(ProjectVO project, Account caller, long callerUserId) throws Exception {
512+
var method = ProjectManagerImpl.class.getDeclaredMethod("cleanupProject", Project.class, AccountVO.class, Long.class);
513+
method.setAccessible(true);
514+
return (boolean) method.invoke(projectManager, project, caller, callerUserId);
515+
}
516+
517+
private ProjectVO mockProject(long id, long projectAccountId) {
518+
ProjectVO project = Mockito.mock(ProjectVO.class);
519+
Mockito.when(project.getId()).thenReturn(id);
520+
Mockito.when(project.getProjectAccountId()).thenReturn(projectAccountId);
521+
return project;
522+
}
523+
320524
private User mockUser(long id, long accountId) {
321525
User user = Mockito.mock(User.class);
322526
Mockito.when(user.getId()).thenReturn(id);
@@ -336,4 +540,13 @@ private ProjectAccountVO mockProjectAccount(long id, Role role) {
336540
Mockito.when(projectAccount.getAccountRole()).thenReturn(role);
337541
return projectAccount;
338542
}
543+
544+
private ProjectAccountVO mockProjectAccountWithIds(long id, long projectId, long accountId, Role role) {
545+
ProjectAccountVO projectAccount = Mockito.mock(ProjectAccountVO.class);
546+
Mockito.lenient().when(projectAccount.getId()).thenReturn(id);
547+
Mockito.lenient().when(projectAccount.getProjectId()).thenReturn(projectId);
548+
Mockito.lenient().when(projectAccount.getAccountId()).thenReturn(accountId);
549+
Mockito.lenient().when(projectAccount.getAccountRole()).thenReturn(role);
550+
return projectAccount;
551+
}
339552
}

0 commit comments

Comments
 (0)