From adf6b588ddb2d61bc4aa8ed4c02edaf292fa825e Mon Sep 17 00:00:00 2001 From: Devdeep Singh Date: Tue, 28 Jul 2015 12:05:35 +0530 Subject: [PATCH 1/2] CLOUDSTACK-8687: Update prepare template api to seed/prepare a template only on a given primary storage. Currently, the prepare template api will seed/prepare a given template on all the primary storage pools in a zone. If however, a user wishes to prepare a template only a particular storage pool, it isn't possible. Updated the api to take storage pool id as an optional parameter. If the pool id is provided then the template is prepared only on the given primary storage pool --- .../cloud/template/TemplateApiService.java | 2 +- .../admin/template/PrepareTemplateCmd.java | 16 +++++- .../cloud/template/TemplateManagerImpl.java | 56 ++++++++++++------- 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/api/src/com/cloud/template/TemplateApiService.java b/api/src/com/cloud/template/TemplateApiService.java index 43177fc521e..7348547cee0 100644 --- a/api/src/com/cloud/template/TemplateApiService.java +++ b/api/src/com/cloud/template/TemplateApiService.java @@ -51,7 +51,7 @@ public interface TemplateApiService { VirtualMachineTemplate copyTemplate(CopyTemplateCmd cmd) throws StorageUnavailableException, ResourceAllocationException; - VirtualMachineTemplate prepareTemplate(long templateId, long zoneId); + VirtualMachineTemplate prepareTemplate(long templateId, long zoneId, Long storageId); boolean detachIso(long vmId); diff --git a/api/src/org/apache/cloudstack/api/command/admin/template/PrepareTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/admin/template/PrepareTemplateCmd.java index d4c26966d91..0537c01fd3c 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/template/PrepareTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/template/PrepareTemplateCmd.java @@ -28,6 +28,7 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ResponseObject.ResponseView; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.StoragePoolResponse; import org.apache.cloudstack.api.response.TemplateResponse; import org.apache.cloudstack.api.response.ZoneResponse; @@ -60,6 +61,15 @@ public class PrepareTemplateCmd extends BaseCmd { description = "template ID of the template to be prepared in primary storage(s).") private Long templateId; + @ACL(accessType = AccessType.OperateEntry) + @Parameter(name = ApiConstants.STORAGE_ID, + type = CommandType.UUID, + entityType = StoragePoolResponse.class, + required = false, + description = "storage pool ID of the primary storage pool to which the template should be prepared. If it is not provided the template" + + " is prepared on all the available primary storage pools.") + private Long storageId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -72,6 +82,10 @@ public class PrepareTemplateCmd extends BaseCmd { return templateId; } + public Long getStorageId() { + return storageId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -90,7 +104,7 @@ public class PrepareTemplateCmd extends BaseCmd { public void execute() { ListResponse response = new ListResponse(); - VirtualMachineTemplate vmTemplate = _templateService.prepareTemplate(templateId, zoneId); + VirtualMachineTemplate vmTemplate = _templateService.prepareTemplate(templateId, zoneId, storageId); List templateResponses = _responseGenerator.createTemplateResponses(ResponseView.Full, vmTemplate, zoneId, true); response.setResponses(templateResponses); response.setResponseName(getCommandName()); diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 6e9af8a0441..0eeab576142 100644 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -436,7 +436,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } @Override - public VirtualMachineTemplate prepareTemplate(long templateId, long zoneId) { + public VirtualMachineTemplate prepareTemplate(long templateId, long zoneId, Long storageId) { VMTemplateVO vmTemplate = _tmpltDao.findById(templateId); if (vmTemplate == null) { @@ -445,7 +445,19 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, _accountMgr.checkAccess(CallContext.current().getCallingAccount(), AccessType.OperateEntry, true, vmTemplate); - prepareTemplateInAllStoragePools(vmTemplate, zoneId); + if (storageId != null) { + StoragePoolVO pool = _poolDao.findById(storageId); + if (pool != null) { + if (pool.getStatus() == StoragePoolStatus.Up && pool.getDataCenterId() == zoneId) { + prepareTemplateInOneStoragePool(vmTemplate, pool); + } else { + s_logger.warn("Skip loading template " + vmTemplate.getId() + " into primary storage " + pool.getId() + " as either the pool zone " + + pool.getDataCenterId() + " is different from the requested zone " + zoneId + " or the pool is currently not available."); + } + } + } else { + prepareTemplateInAllStoragePools(vmTemplate, zoneId); + } return vmTemplate; } @@ -556,28 +568,32 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } } + private void prepareTemplateInOneStoragePool(final VMTemplateVO template, final StoragePoolVO pool) { + s_logger.info("Schedule to preload template " + template.getId() + " into primary storage " + pool.getId()); + _preloadExecutor.execute(new ManagedContextRunnable() { + @Override + protected void runInContext() { + try { + reallyRun(); + } catch (Throwable e) { + s_logger.warn("Unexpected exception ", e); + } + } + + private void reallyRun() { + s_logger.info("Start to preload template " + template.getId() + " into primary storage " + pool.getId()); + StoragePool pol = (StoragePool)_dataStoreMgr.getPrimaryDataStore(pool.getId()); + prepareTemplateForCreate(template, pol); + s_logger.info("End of preloading template " + template.getId() + " into primary storage " + pool.getId()); + } + }); + } + public void prepareTemplateInAllStoragePools(final VMTemplateVO template, long zoneId) { List pools = _poolDao.listByStatus(StoragePoolStatus.Up); for (final StoragePoolVO pool : pools) { if (pool.getDataCenterId() == zoneId) { - s_logger.info("Schedule to preload template " + template.getId() + " into primary storage " + pool.getId()); - _preloadExecutor.execute(new ManagedContextRunnable() { - @Override - protected void runInContext() { - try { - reallyRun(); - } catch (Throwable e) { - s_logger.warn("Unexpected exception ", e); - } - } - - private void reallyRun() { - s_logger.info("Start to preload template " + template.getId() + " into primary storage " + pool.getId()); - StoragePool pol = (StoragePool)_dataStoreMgr.getPrimaryDataStore(pool.getId()); - prepareTemplateForCreate(template, pol); - s_logger.info("End of preloading template " + template.getId() + " into primary storage " + pool.getId()); - } - }); + prepareTemplateInOneStoragePool(template, pool); } else { s_logger.info("Skip loading template " + template.getId() + " into primary storage " + pool.getId() + " as pool zone " + pool.getDataCenterId() + " is different from the requested zone " + zoneId); From fedef2e6caefd41ad10ac3d691a28271e101f171 Mon Sep 17 00:00:00 2001 From: Devdeep Singh Date: Tue, 4 Aug 2015 17:17:10 +0530 Subject: [PATCH 2/2] CLOUDSTACK-8687: Unit tests for validating the prepare template functionality. These tests validate that the templates get scheduled for seeding. Additionally, if a template is already seeded, we do not try and seed it again. Tests also validate that templates are seeded to storage pools which are available. --- .../cloud/template/TemplateManagerImpl.java | 4 +- .../template/TemplateManagerImplTest.java | 520 +++++++++++++++++- 2 files changed, 518 insertions(+), 6 deletions(-) diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 0eeab576142..391134099e0 100644 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -269,10 +269,10 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, MessageBus _messageBus; private boolean _disableExtraction = false; - private ExecutorService _preloadExecutor; - private List _adapters; + ExecutorService _preloadExecutor; + @Inject private StorageCacheManager cacheMgr; @Inject diff --git a/server/test/com/cloud/template/TemplateManagerImplTest.java b/server/test/com/cloud/template/TemplateManagerImplTest.java index bcbc3234746..ed4ec520a98 100644 --- a/server/test/com/cloud/template/TemplateManagerImplTest.java +++ b/server/test/com/cloud/template/TemplateManagerImplTest.java @@ -18,20 +18,532 @@ package com.cloud.template; -import org.junit.Test; +import com.cloud.agent.AgentManager; +import com.cloud.api.query.dao.UserVmJoinDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.domain.dao.DomainDao; +import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.host.Status; +import com.cloud.host.dao.HostDao; +import com.cloud.projects.ProjectManager; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.LaunchPermissionDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VMTemplateZoneDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.User; +import com.cloud.user.UserVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.StorageCacheManager; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; +import org.apache.cloudstack.test.utils.SpringUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; +import javax.inject.Inject; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(loader = AnnotationConfigContextLoader.class) public class TemplateManagerImplTest { - TemplateManagerImpl tmgr = new TemplateManagerImpl(); + @Inject + TemplateManagerImpl templateManager = new TemplateManagerImpl(); + + @Inject + DataStoreManager dataStoreManager; + + @Inject + VMTemplateDao vmTemplateDao; + + @Inject + VMTemplatePoolDao vmTemplatePoolDao; + + @Inject + TemplateDataStoreDao templateDataStoreDao; + + @Inject + StoragePoolHostDao storagePoolHostDao; + + @Inject + PrimaryDataStoreDao primaryDataStoreDao; + + public class CustomThreadPoolExecutor extends ThreadPoolExecutor { + AtomicInteger ai = new AtomicInteger(0); + public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, + BlockingQueue workQueue, ThreadFactory threadFactory) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); + } + + @Override + protected void beforeExecute(Thread t, Runnable r) { + ai.addAndGet(1); + } + + public int getCount() { + try { + // Wait for some time to give before execute to run. Otherwise the tests that + // assert and check that template seeding has been scheduled may fail. If tests + // are seen to fail, consider increasing the sleep time. + Thread.sleep(1000); + return ai.get(); + } catch (Exception e) { + return -1; + } + } + } + + @Before + public void setUp() { + ComponentContext.initComponentsLifeCycle(); + AccountVO account = new AccountVO("admin", 1L, "networkDomain", Account.ACCOUNT_TYPE_NORMAL, "uuid"); + UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN); + CallContext.register(user, account); + } + + @After + public void tearDown() { + CallContext.unregister(); + } @Test(expected = InvalidParameterValueException.class) public void testVerifyTemplateIdOfSystemTemplate() { - tmgr.verifyTemplateId(1L); + templateManager.verifyTemplateId(1L); } public void testVerifyTemplateIdOfNonSystemTemplate() { - tmgr.verifyTemplateId(1L); + templateManager.verifyTemplateId(1L); + } + + @Test + public void testPrepareTemplateIsSeeded() { + VMTemplateVO mockTemplate = mock(VMTemplateVO.class); + when(mockTemplate.getId()).thenReturn(202l); + + StoragePoolVO mockPool = mock(StoragePoolVO.class); + when(mockPool.getId()).thenReturn(2l); + + PrimaryDataStore mockPrimaryDataStore = mock(PrimaryDataStore.class); + when(mockPrimaryDataStore.getId()).thenReturn(2l); + + VMTemplateStoragePoolVO mockTemplateStore = mock(VMTemplateStoragePoolVO.class); + when(mockTemplateStore.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + + when(dataStoreManager.getPrimaryDataStore(anyLong())).thenReturn(mockPrimaryDataStore); + when(vmTemplateDao.findById(anyLong(), anyBoolean())).thenReturn(mockTemplate); + when(vmTemplatePoolDao.findByPoolTemplate(anyLong(), anyLong())).thenReturn(mockTemplateStore); + + doNothing().when(mockTemplateStore).setMarkedForGC(anyBoolean()); + + VMTemplateStoragePoolVO returnObject = templateManager.prepareTemplateForCreate(mockTemplate, (StoragePool) mockPrimaryDataStore); + assertTrue("Test template is already seeded", returnObject == mockTemplateStore); + } + + @Test + public void testPrepareTemplateNotDownloaded() { + VMTemplateVO mockTemplate = mock(VMTemplateVO.class); + when(mockTemplate.getId()).thenReturn(202l); + + StoragePoolVO mockPool = mock(StoragePoolVO.class); + when(mockPool.getId()).thenReturn(2l); + + PrimaryDataStore mockPrimaryDataStore = mock(PrimaryDataStore.class); + when(mockPrimaryDataStore.getId()).thenReturn(2l); + when(mockPrimaryDataStore.getDataCenterId()).thenReturn(1l); + + when(dataStoreManager.getPrimaryDataStore(anyLong())).thenReturn(mockPrimaryDataStore); + when(vmTemplateDao.findById(anyLong(), anyBoolean())).thenReturn(mockTemplate); + when(vmTemplatePoolDao.findByPoolTemplate(anyLong(), anyLong())).thenReturn(null); + when(templateDataStoreDao.findByTemplateZoneDownloadStatus(202l, 1l, VMTemplateStorageResourceAssoc.Status.DOWNLOADED)).thenReturn(null); + + VMTemplateStoragePoolVO returnObject = templateManager.prepareTemplateForCreate(mockTemplate, (StoragePool) mockPrimaryDataStore); + assertTrue("Test template is not ready", returnObject == null); + } + + @Test(expected = CloudRuntimeException.class) + public void testPrepareTemplateNoHostConnectedToPool() { + VMTemplateVO mockTemplate = mock(VMTemplateVO.class); + when(mockTemplate.getId()).thenReturn(202l); + + StoragePoolVO mockPool = mock(StoragePoolVO.class); + when(mockPool.getId()).thenReturn(2l); + + PrimaryDataStore mockPrimaryDataStore = mock(PrimaryDataStore.class); + when(mockPrimaryDataStore.getId()).thenReturn(2l); + when(mockPrimaryDataStore.getDataCenterId()).thenReturn(1l); + + TemplateDataStoreVO mockTemplateDataStore = mock(TemplateDataStoreVO.class); + + when(dataStoreManager.getPrimaryDataStore(anyLong())).thenReturn(mockPrimaryDataStore); + when(vmTemplateDao.findById(anyLong(), anyBoolean())).thenReturn(mockTemplate); + when(vmTemplatePoolDao.findByPoolTemplate(anyLong(), anyLong())).thenReturn(null); + when(templateDataStoreDao.findByTemplateZoneDownloadStatus(202l, 1l, VMTemplateStorageResourceAssoc.Status.DOWNLOADED)).thenReturn(mockTemplateDataStore); + when(storagePoolHostDao.listByHostStatus(2l, Status.Up)).thenReturn(null); + + templateManager.prepareTemplateForCreate(mockTemplate, (StoragePool) mockPrimaryDataStore); + } + + @Test(expected = InvalidParameterValueException.class) + public void testPrepareTemplateInvalidTemplate() { + when(vmTemplateDao.findById(anyLong())).thenReturn(null); + templateManager.prepareTemplate(202, 1, null); + } + + @Test + public void testTemplateScheduledForDownloadInOnePool() { + VMTemplateVO mockTemplate = mock(VMTemplateVO.class); + StoragePoolVO mockPool = mock(StoragePoolVO.class); + PrimaryDataStore mockPrimaryDataStore = mock(PrimaryDataStore.class); + VMTemplateStoragePoolVO mockTemplateStore = mock(VMTemplateStoragePoolVO.class); + + when(mockPrimaryDataStore.getId()).thenReturn(2l); + when(mockPool.getId()).thenReturn(2l); + when(mockPool.getStatus()).thenReturn(StoragePoolStatus.Up); + when(mockPool.getDataCenterId()).thenReturn(1l); + when(mockTemplate.getId()).thenReturn(202l); + when(mockTemplateStore.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + when(vmTemplateDao.findById(anyLong())).thenReturn(mockTemplate); + when(dataStoreManager.getPrimaryDataStore(anyLong())).thenReturn(mockPrimaryDataStore); + when(vmTemplateDao.findById(anyLong(), anyBoolean())).thenReturn(mockTemplate); + when(vmTemplatePoolDao.findByPoolTemplate(anyLong(), anyLong())).thenReturn(mockTemplateStore); + when(primaryDataStoreDao.findById(anyLong())).thenReturn(mockPool); + + doNothing().when(mockTemplateStore).setMarkedForGC(anyBoolean()); + + ExecutorService preloadExecutor = new CustomThreadPoolExecutor(8, 8, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), + new NamedThreadFactory("Template-Preloader")); + templateManager._preloadExecutor = preloadExecutor; + + templateManager.prepareTemplate(202, 1, 2l); + assertTrue("Test template is scheduled for seeding to on pool", ((CustomThreadPoolExecutor)preloadExecutor).getCount() == 1); + } + + @Test + public void testTemplateScheduledForDownloadInDisabledPool() { + VMTemplateVO mockTemplate = mock(VMTemplateVO.class); + StoragePoolVO mockPool = mock(StoragePoolVO.class); + PrimaryDataStore mockPrimaryDataStore = mock(PrimaryDataStore.class); + VMTemplateStoragePoolVO mockTemplateStore = mock(VMTemplateStoragePoolVO.class); + + when(mockPrimaryDataStore.getId()).thenReturn(2l); + when(mockPool.getId()).thenReturn(2l); + when(mockPool.getStatus()).thenReturn(StoragePoolStatus.Disabled); + when(mockPool.getDataCenterId()).thenReturn(1l); + when(mockTemplate.getId()).thenReturn(202l); + when(mockTemplateStore.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + when(vmTemplateDao.findById(anyLong())).thenReturn(mockTemplate); + when(dataStoreManager.getPrimaryDataStore(anyLong())).thenReturn(mockPrimaryDataStore); + when(vmTemplateDao.findById(anyLong(), anyBoolean())).thenReturn(mockTemplate); + when(vmTemplatePoolDao.findByPoolTemplate(anyLong(), anyLong())).thenReturn(mockTemplateStore); + when(primaryDataStoreDao.findById(anyLong())).thenReturn(mockPool); + + doNothing().when(mockTemplateStore).setMarkedForGC(anyBoolean()); + + ExecutorService preloadExecutor = new CustomThreadPoolExecutor(8, 8, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), + new NamedThreadFactory("Template-Preloader")); + templateManager._preloadExecutor = preloadExecutor; + + templateManager.prepareTemplate(202, 1, 2l); + assertTrue("Test template is not scheduled for seeding on disabled pool", ((CustomThreadPoolExecutor)preloadExecutor).getCount() == 0); + } + + @Test + public void testTemplateScheduledForDownloadInMultiplePool() { + VMTemplateVO mockTemplate = mock(VMTemplateVO.class); + PrimaryDataStore mockPrimaryDataStore = mock(PrimaryDataStore.class); + VMTemplateStoragePoolVO mockTemplateStore = mock(VMTemplateStoragePoolVO.class); + List pools = new ArrayList(); + + StoragePoolVO mockPool1 = mock(StoragePoolVO.class); + when(mockPool1.getId()).thenReturn(2l); + when(mockPool1.getStatus()).thenReturn(StoragePoolStatus.Up); + when(mockPool1.getDataCenterId()).thenReturn(1l); + StoragePoolVO mockPool2 = mock(StoragePoolVO.class); + when(mockPool2.getId()).thenReturn(3l); + when(mockPool2.getStatus()).thenReturn(StoragePoolStatus.Up); + when(mockPool2.getDataCenterId()).thenReturn(1l); + StoragePoolVO mockPool3 = mock(StoragePoolVO.class); + when(mockPool3.getId()).thenReturn(4l); + when(mockPool3.getStatus()).thenReturn(StoragePoolStatus.Up); + when(mockPool3.getDataCenterId()).thenReturn(2l); + pools.add(mockPool1); + pools.add(mockPool2); + pools.add(mockPool3); + + when(mockPrimaryDataStore.getId()).thenReturn(2l); + when(mockTemplate.getId()).thenReturn(202l); + when(mockTemplateStore.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + when(vmTemplateDao.findById(anyLong())).thenReturn(mockTemplate); + when(dataStoreManager.getPrimaryDataStore(anyLong())).thenReturn(mockPrimaryDataStore); + when(vmTemplateDao.findById(anyLong(), anyBoolean())).thenReturn(mockTemplate); + when(vmTemplatePoolDao.findByPoolTemplate(anyLong(), anyLong())).thenReturn(mockTemplateStore); + when(primaryDataStoreDao.findById(2l)).thenReturn(mockPool1); + when(primaryDataStoreDao.findById(3l)).thenReturn(mockPool2); + when(primaryDataStoreDao.findById(4l)).thenReturn(mockPool3); + when(primaryDataStoreDao.listByStatus(StoragePoolStatus.Up)).thenReturn(pools); + + doNothing().when(mockTemplateStore).setMarkedForGC(anyBoolean()); + + ExecutorService preloadExecutor = new CustomThreadPoolExecutor(8, 8, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), + new NamedThreadFactory("Template-Preloader")); + templateManager._preloadExecutor = preloadExecutor; + + templateManager.prepareTemplate(202, 1, null); + assertTrue("Test template is scheduled for seeding to on pool", ((CustomThreadPoolExecutor) preloadExecutor).getCount() == 2); + } + + @Configuration + @ComponentScan(basePackageClasses = {TemplateManagerImpl.class}, + includeFilters = {@ComponentScan.Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM)}, + useDefaultFilters = false) + public static class TestConfiguration extends SpringUtils.CloudStackTestConfiguration { + + @Bean + public DataStoreManager dataStoreManager() { + return Mockito.mock(DataStoreManager.class); + } + + @Bean + public VMTemplateDao vmTemplateDao() { + return Mockito.mock(VMTemplateDao.class); + } + + @Bean + public VMTemplatePoolDao vmTemplatePoolDao() { + return Mockito.mock(VMTemplatePoolDao.class); + } + + @Bean + public TemplateDataStoreDao templateDataStoreDao() { + return Mockito.mock(TemplateDataStoreDao.class); + } + + @Bean + public VMTemplateZoneDao vmTemplateZoneDao() { + return Mockito.mock(VMTemplateZoneDao.class); + } + + @Bean + public VMInstanceDao vmInstanceDao() { + return Mockito.mock(VMInstanceDao.class); + } + + @Bean + public PrimaryDataStoreDao primaryDataStoreDao() { + return Mockito.mock(PrimaryDataStoreDao.class); + } + + @Bean + public StoragePoolHostDao storagePoolHostDao() { + return Mockito.mock(StoragePoolHostDao.class); + } + + @Bean + public AccountDao accountDao() { + return Mockito.mock(AccountDao.class); + } + + @Bean + public AgentManager agentMgr() { + return Mockito.mock(AgentManager.class); + } + + @Bean + public AccountManager accountManager() { + return Mockito.mock(AccountManager.class); + } + + @Bean + public HostDao hostDao() { + return Mockito.mock(HostDao.class); + } + + @Bean + public DataCenterDao dcDao() { + return Mockito.mock(DataCenterDao.class); + } + + @Bean + public UserVmDao userVmDao() { + return Mockito.mock(UserVmDao.class); + } + + @Bean + public VolumeDao volumeDao() { + return Mockito.mock(VolumeDao.class); + } + + @Bean + public SnapshotDao snapshotDao() { + return Mockito.mock(SnapshotDao.class); + } + + @Bean + public ConfigurationDao configDao() { + return Mockito.mock(ConfigurationDao.class); + } + + @Bean + public DomainDao domainDao() { + return Mockito.mock(DomainDao.class); + } + + @Bean + public GuestOSDao guestOSDao() { + return Mockito.mock(GuestOSDao.class); + } + + @Bean + public StorageManager storageManager() { + return Mockito.mock(StorageManager.class); + } + + @Bean + public UsageEventDao usageEventDao() { + return Mockito.mock(UsageEventDao.class); + } + + @Bean + public ResourceLimitService resourceLimitMgr() { + return Mockito.mock(ResourceLimitService.class); + } + + @Bean + public LaunchPermissionDao launchPermissionDao() { + return Mockito.mock(LaunchPermissionDao.class); + } + + @Bean + public ProjectManager projectMgr() { + return Mockito.mock(ProjectManager.class); + } + + @Bean + public VolumeDataFactory volFactory() { + return Mockito.mock(VolumeDataFactory.class); + } + + @Bean + public TemplateDataFactory tmplFactory() { + return Mockito.mock(TemplateDataFactory.class); + } + + @Bean + public SnapshotDataFactory snapshotFactory() { + return Mockito.mock(SnapshotDataFactory.class); + } + + @Bean + public TemplateService tmpltSvr() { + return Mockito.mock(TemplateService.class); + } + + @Bean + public VolumeOrchestrationService volumeMgr() { + return Mockito.mock(VolumeOrchestrationService.class); + } + + @Bean + public EndPointSelector epSelector() { + return Mockito.mock(EndPointSelector.class); + } + + @Bean + public UserVmJoinDao userVmJoinDao() { + return Mockito.mock(UserVmJoinDao.class); + } + + @Bean + public SnapshotDataStoreDao snapshotStoreDao() { + return Mockito.mock(SnapshotDataStoreDao.class); + } + + @Bean + public MessageBus messageBus() { + return Mockito.mock(MessageBus.class); + } + + @Bean + public StorageCacheManager cacheMgr() { + return Mockito.mock(StorageCacheManager.class); + } + + @Bean + public TemplateAdapter templateAdapter() { + return Mockito.mock(TemplateAdapter.class); + } + + public static class Library implements TypeFilter { + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + ComponentScan cs = TestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + } } }