// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package com.cloud.storage.snapshot; import com.cloud.configuration.Resource.ResourceType; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceAllocationException; import com.cloud.hypervisor.Hypervisor; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.storage.DataStoreRole; import com.cloud.storage.ScopeType; import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.SnapshotDao; 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.utils.exception.CloudRuntimeException; import com.cloud.vm.UserVmVO; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.dao.VMSnapshotDao; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy.SnapshotOperation; import org.apache.cloudstack.engine.subsystem.api.storage.StorageStrategyFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.Spy; import java.util.List; import java.util.UUID; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class SnapshotManagerTest { @Spy SnapshotManagerImpl _snapshotMgr = new SnapshotManagerImpl(); @Mock SnapshotDao _snapshotDao; @Mock VolumeDao _volumeDao; @Mock UserVmDao _vmDao; @Mock PrimaryDataStoreDao _storagePoolDao; @Mock VMSnapshotDao _vmSnapshotDao; @Mock VMSnapshotVO vmSnapshotMock; @Mock Account account; @Mock UserVmVO vmMock; @Mock VolumeVO volumeMock; @Mock VolumeInfo volumeInfoMock; @Mock VolumeDataFactory volumeFactory; @Mock SnapshotVO snapshotMock; @Mock SnapshotInfo snapshotInfoMock; @Mock SnapshotDataFactory snapshotFactory; @Mock StorageStrategyFactory _storageStrategyFactory; @Mock SnapshotStrategy snapshotStrategy; @Mock AccountManager _accountMgr; @Mock ResourceLimitService _resourceLimitMgr; @Mock StoragePoolVO poolMock; @Mock ResourceManager _resourceMgr; @Mock DataStore storeMock; @Mock SnapshotDataStoreDao _snapshotStoreDao; @Mock SnapshotDataStoreVO snapshotStoreMock; private static final long TEST_SNAPSHOT_ID = 3L; private static final long TEST_VOLUME_ID = 4L; private static final long TEST_VM_ID = 5L; private static final long TEST_STORAGE_POOL_ID = 6L; private static final long TEST_VM_SNAPSHOT_ID = 6L; @Before public void setup() throws ResourceAllocationException { MockitoAnnotations.initMocks(this); _snapshotMgr._snapshotDao = _snapshotDao; _snapshotMgr._volsDao = _volumeDao; _snapshotMgr._vmDao = _vmDao; _snapshotMgr.volFactory = volumeFactory; _snapshotMgr.snapshotFactory = snapshotFactory; _snapshotMgr._storageStrategyFactory = _storageStrategyFactory; _snapshotMgr._accountMgr = _accountMgr; _snapshotMgr._resourceLimitMgr = _resourceLimitMgr; _snapshotMgr._storagePoolDao = _storagePoolDao; _snapshotMgr._resourceMgr = _resourceMgr; _snapshotMgr._vmSnapshotDao = _vmSnapshotDao; _snapshotMgr._snapshotStoreDao = _snapshotStoreDao; when(_snapshotDao.findById(anyLong())).thenReturn(snapshotMock); when(snapshotMock.getVolumeId()).thenReturn(TEST_VOLUME_ID); when(snapshotMock.isRecursive()).thenReturn(false); when(_volumeDao.findById(anyLong())).thenReturn(volumeMock); when(volumeMock.getState()).thenReturn(Volume.State.Ready); when(volumeFactory.getVolume(anyLong())).thenReturn(volumeInfoMock); when(volumeInfoMock.getDataStore()).thenReturn(storeMock); when(volumeInfoMock.getState()).thenReturn(Volume.State.Ready); when(storeMock.getId()).thenReturn(TEST_STORAGE_POOL_ID); when(snapshotFactory.getSnapshot(anyLong(), Mockito.any(DataStoreRole.class))).thenReturn(snapshotInfoMock); when(_storageStrategyFactory.getSnapshotStrategy(Mockito.any(SnapshotVO.class), Mockito.eq(SnapshotOperation.BACKUP))).thenReturn(snapshotStrategy); when(_storageStrategyFactory.getSnapshotStrategy(Mockito.any(SnapshotVO.class), Mockito.eq(SnapshotOperation.REVERT))).thenReturn(snapshotStrategy); when(_storageStrategyFactory.getSnapshotStrategy(Mockito.any(SnapshotVO.class), Mockito.eq(SnapshotOperation.DELETE))).thenReturn(snapshotStrategy); doNothing().when(_accountMgr).checkAccess(any(Account.class), any(AccessType.class), any(Boolean.class), any(ControlledEntity.class)); doNothing().when(_snapshotMgr._resourceLimitMgr).checkResourceLimit(any(Account.class), any(ResourceType.class)); doNothing().when(_snapshotMgr._resourceLimitMgr).checkResourceLimit(any(Account.class), any(ResourceType.class), anyLong()); doNothing().when(_snapshotMgr._resourceLimitMgr).decrementResourceCount(anyLong(), any(ResourceType.class), anyLong()); doNothing().when(_snapshotMgr._resourceLimitMgr).incrementResourceCount(anyLong(), any(ResourceType.class)); doNothing().when(_snapshotMgr._resourceLimitMgr).incrementResourceCount(anyLong(), any(ResourceType.class), anyLong()); Account account = new AccountVO("testaccount", 1L, "networkdomain", (short)0, "uuid"); UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN); CallContext.register(user, account); when(_accountMgr.getAccount(anyLong())).thenReturn(account); when(_storagePoolDao.findById(anyLong())).thenReturn(poolMock); when(poolMock.getScope()).thenReturn(ScopeType.ZONE); when(poolMock.getHypervisor()).thenReturn(HypervisorType.KVM); when(_resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(any(HypervisorType.class), anyLong())).thenReturn(null); } @After public void tearDown() { CallContext.unregister(); } // vm is destroyed @Test(expected = CloudRuntimeException.class) public void testAllocSnapshotF1() throws ResourceAllocationException { when(_vmDao.findById(anyLong())).thenReturn(vmMock); when(vmMock.getState()).thenReturn(State.Destroyed); _snapshotMgr.allocSnapshot(TEST_VOLUME_ID, Snapshot.MANUAL_POLICY_ID, null, null); } // active snapshots @SuppressWarnings("unchecked") @Test(expected = InvalidParameterValueException.class) public void testAllocSnapshotF2() throws ResourceAllocationException { when(_vmDao.findById(anyLong())).thenReturn(vmMock); when(vmMock.getId()).thenReturn(TEST_VM_ID); when(vmMock.getState()).thenReturn(State.Stopped); when(vmMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); when(volumeInfoMock.getInstanceId()).thenReturn(TEST_VM_ID); List<SnapshotVO> mockList = mock(List.class); when(mockList.size()).thenReturn(1); when(_snapshotDao.listByInstanceId(TEST_VM_ID, Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp)).thenReturn(mockList); _snapshotMgr.allocSnapshot(TEST_VOLUME_ID, Snapshot.MANUAL_POLICY_ID, null, null); } // active vm snapshots @SuppressWarnings("unchecked") @Test(expected = CloudRuntimeException.class) public void testAllocSnapshotF3() throws ResourceAllocationException { when(_vmDao.findById(anyLong())).thenReturn(vmMock); when(vmMock.getId()).thenReturn(TEST_VM_ID); when(vmMock.getState()).thenReturn(State.Stopped); when(vmMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); when(volumeInfoMock.getInstanceId()).thenReturn(TEST_VM_ID); List<SnapshotVO> mockList = mock(List.class); when(mockList.size()).thenReturn(0); when(_snapshotDao.listByInstanceId(TEST_VM_ID, Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp)).thenReturn(mockList); List<VMSnapshotVO> mockList2 = mock(List.class); when(mockList2.size()).thenReturn(1); when(_vmSnapshotDao.listByInstanceId(TEST_VM_ID, VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging)).thenReturn(mockList2); _snapshotMgr.allocSnapshot(TEST_VOLUME_ID, Snapshot.MANUAL_POLICY_ID, null, null); } // successful test @SuppressWarnings("unchecked") @Test public void testAllocSnapshotF4() throws ResourceAllocationException { when(_vmDao.findById(anyLong())).thenReturn(vmMock); when(vmMock.getId()).thenReturn(TEST_VM_ID); when(vmMock.getState()).thenReturn(State.Stopped); when(vmMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); when(volumeInfoMock.getInstanceId()).thenReturn(TEST_VM_ID); List<SnapshotVO> mockList = mock(List.class); when(mockList.size()).thenReturn(0); when(_snapshotDao.listByInstanceId(TEST_VM_ID, Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp)).thenReturn(mockList); List<VMSnapshotVO> mockList2 = mock(List.class); when(mockList2.size()).thenReturn(0); when(_vmSnapshotDao.listByInstanceId(TEST_VM_ID, VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging)).thenReturn(mockList2); when(_snapshotDao.persist(any(SnapshotVO.class))).thenReturn(snapshotMock); _snapshotMgr.allocSnapshot(TEST_VOLUME_ID, Snapshot.MANUAL_POLICY_ID, null, null); } @Test(expected = InvalidParameterValueException.class) public void testDeleteSnapshotF1() { when(snapshotStrategy.deleteSnapshot(TEST_SNAPSHOT_ID)).thenReturn(true); when(snapshotMock.getState()).thenReturn(Snapshot.State.Destroyed); when(snapshotMock.getAccountId()).thenReturn(2L); when(snapshotMock.getDataCenterId()).thenReturn(2L); _snapshotMgr.deleteSnapshot(TEST_SNAPSHOT_ID); } // vm state not stopped @Test(expected = InvalidParameterValueException.class) public void testRevertSnapshotF1() { when(volumeMock.getInstanceId()).thenReturn(TEST_VM_ID); when(_vmDao.findById(anyLong())).thenReturn(vmMock); when(vmMock.getState()).thenReturn(State.Running); _snapshotMgr.revertSnapshot(TEST_SNAPSHOT_ID); } // vm on Xenserver, return null @Test public void testRevertSnapshotF2() { when(_vmDao.findById(anyLong())).thenReturn(vmMock); when(vmMock.getState()).thenReturn(State.Stopped); when(vmMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.XenServer); when(volumeMock.getFormat()).thenReturn(ImageFormat.VHD); Snapshot snapshot = _snapshotMgr.revertSnapshot(TEST_SNAPSHOT_ID); Assert.assertNull(snapshot); } // vm on KVM, successful @Test public void testRevertSnapshotF3() { when(_vmDao.findById(anyLong())).thenReturn(vmMock); when(vmMock.getState()).thenReturn(State.Stopped); when(vmMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); when(volumeMock.getFormat()).thenReturn(ImageFormat.QCOW2); when (snapshotStrategy.revertSnapshot(Mockito.any(SnapshotInfo.class))).thenReturn(true); when(_volumeDao.update(anyLong(), any(VolumeVO.class))).thenReturn(true); Snapshot snapshot = _snapshotMgr.revertSnapshot(TEST_SNAPSHOT_ID); Assert.assertNotNull(snapshot); } // vm on Xenserver, expected exception @Test(expected = InvalidParameterValueException.class) public void testBackupSnapshotFromVmSnapshotF1() { when(_vmDao.findById(anyLong())).thenReturn(vmMock); when(vmMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.XenServer); Snapshot snapshot = _snapshotMgr.backupSnapshotFromVmSnapshot(TEST_SNAPSHOT_ID, TEST_VM_ID, TEST_VOLUME_ID, TEST_VM_SNAPSHOT_ID); Assert.assertNull(snapshot); } // vm on KVM, first time @Test public void testBackupSnapshotFromVmSnapshotF2() { when(_vmDao.findById(anyLong())).thenReturn(vmMock); when(vmMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); when(_vmSnapshotDao.findById(anyLong())).thenReturn(vmSnapshotMock); when(_snapshotStoreDao.findParent(any(DataStoreRole.class), anyLong(), anyLong())).thenReturn(null); when(snapshotFactory.getSnapshot(anyLong(), Mockito.any(DataStore.class))).thenReturn(snapshotInfoMock); when(storeMock.create(snapshotInfoMock)).thenReturn(snapshotInfoMock); when(_snapshotStoreDao.findBySnapshot(anyLong(), any(DataStoreRole.class))).thenReturn(snapshotStoreMock); when(_snapshotStoreDao.update(anyLong(), any(SnapshotDataStoreVO.class))).thenReturn(true); when(_snapshotDao.update(anyLong(), any(SnapshotVO.class))).thenReturn(true); when(vmMock.getAccountId()).thenReturn(2L); when(snapshotStrategy.backupSnapshot(any(SnapshotInfo.class))).thenReturn(snapshotInfoMock);;; Snapshot snapshot = _snapshotMgr.backupSnapshotFromVmSnapshot(TEST_SNAPSHOT_ID, TEST_VM_ID, TEST_VOLUME_ID, TEST_VM_SNAPSHOT_ID); Assert.assertNotNull(snapshot); } // vm on KVM, already backed up @Test(expected = InvalidParameterValueException.class) public void testBackupSnapshotFromVmSnapshotF3() { when(_vmDao.findById(anyLong())).thenReturn(vmMock); when(vmMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); when(_vmSnapshotDao.findById(anyLong())).thenReturn(vmSnapshotMock); when(_snapshotStoreDao.findParent(any(DataStoreRole.class), anyLong(), anyLong())).thenReturn(snapshotStoreMock); when(snapshotStoreMock.getInstallPath()).thenReturn("VM_SNAPSHOT_NAME"); when(vmSnapshotMock.getName()).thenReturn("VM_SNAPSHOT_NAME"); Snapshot snapshot = _snapshotMgr.backupSnapshotFromVmSnapshot(TEST_SNAPSHOT_ID, TEST_VM_ID, TEST_VOLUME_ID, TEST_VM_SNAPSHOT_ID); Assert.assertNull(snapshot); } }