// 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.user; import com.cloud.domain.DomainVO; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; import com.cloud.event.UsageEventVO; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.CloudException; import com.cloud.exception.ConcurrentOperationException; import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.Volume.Type; import com.cloud.storage.VolumeVO; import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmManagerImpl; import com.cloud.vm.UserVmVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.dao.VmStatsDao; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplTestBase { private static final Long ACCOUNT_ID = 1l; private static final String VOLUME_UUID = "vol-111111"; @Spy @InjectMocks private UserVmManagerImpl _vmMgr; @Mock private UserVmManager userVmManager; @Mock private VmStatsDao vmStatsDaoMock; Map oldFields = new HashMap<>(); UserVmVO vm = mock(UserVmVO.class); // Configures the static fields of the UsageEventUtils class, Storing the // previous values to be restored during the cleanup phase, to avoid // interference with other unit tests. protected UsageEventUtils setupUsageUtils() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { _usageEventDao = new MockUsageEventDao(); UsageEventUtils utils = new UsageEventUtils(); List usageUtilsFields = new ArrayList(); usageUtilsFields.add("usageEventDao"); usageUtilsFields.add("accountDao"); usageUtilsFields.add("dcDao"); usageUtilsFields.add("configDao"); for (String fieldName : usageUtilsFields) { try { Field f = UsageEventUtils.class.getDeclaredField(fieldName); f.setAccessible(true); Field staticField = UsageEventUtils.class.getDeclaredField("s_" + fieldName); staticField.setAccessible(true); oldFields.put(f.getName(), staticField.get(null)); f.set(utils, this.getClass().getSuperclass().getDeclaredField("_" + fieldName).get(this)); } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { e.printStackTrace(); } } Method method; method = UsageEventUtils.class.getDeclaredMethod("init"); method.setAccessible(true); method.invoke(utils); return utils; } protected void defineMocksBehavior() throws AgentUnavailableException, ConcurrentOperationException, CloudException { AccountVO account = new AccountVO(); account.setId(ACCOUNT_ID); when(_accountDao.remove(ACCOUNT_ID)).thenReturn(true); when(_accountDao.findById(ACCOUNT_ID)).thenReturn(account); DomainVO domain = new DomainVO(); VirtualMachineEntity vmEntity = mock(VirtualMachineEntity.class); lenient().when(_orchSrvc.getVirtualMachine(nullable(String.class))).thenReturn(vmEntity); lenient().when(vmEntity.destroy(nullable(Boolean.class))).thenReturn(true); lenient().doReturn(vm).when(_vmDao).findById(nullable(Long.class)); VolumeVO vol = new VolumeVO(VOLUME_UUID, 1l, 1l, 1l, 1l, 1l, "folder", "path", null, 50, Type.ROOT); vol.setDisplayVolume(true); List volumes = new ArrayList<>(); volumes.add(vol); lenient().when(securityChecker.checkAccess(Mockito.eq(account), nullable(ControlledEntity.class), nullable(AccessType.class), nullable(String.class))).thenReturn(true); lenient().when(_userVmDao.findById(nullable(Long.class))).thenReturn(vm); lenient().when(_userVmDao.listByAccountId(ACCOUNT_ID)).thenReturn(Arrays.asList(vm)); lenient().when(_userVmDao.findByUuid(nullable(String.class))).thenReturn(vm); lenient().when(_volumeDao.findByInstance(nullable(Long.class))).thenReturn(volumes); ServiceOfferingVO offering = mock(ServiceOfferingVO.class); lenient().when(offering.getCpu()).thenReturn(500); lenient().when(offering.getId()).thenReturn(1l); lenient().when(serviceOfferingDao.findByIdIncludingRemoved(nullable(Long.class), nullable(Long.class))).thenReturn(offering); lenient().when(_domainMgr.getDomain(nullable(Long.class))).thenReturn(domain); lenient().doReturn(true).when(_vmMgr).expunge(any(UserVmVO.class)); } @Before public void init() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, AgentUnavailableException, ConcurrentOperationException, CloudException { setupUsageUtils(); defineMocksBehavior(); } @After // Restores static fields of the UsageEventUtil class to previous values. public void cleanupUsageUtils() throws ReflectiveOperationException, SecurityException { UsageEventUtils utils = new UsageEventUtils(); for (String fieldName : oldFields.keySet()) { Field f = UsageEventUtils.class.getDeclaredField(fieldName); f.setAccessible(true); f.set(utils, oldFields.get(fieldName)); } Method method = UsageEventUtils.class.getDeclaredMethod("init"); method.setAccessible(true); method.invoke(utils); } protected List deleteUserAccountRootVolumeUsageEvents(boolean vmDestroyedPrior) throws AgentUnavailableException, ConcurrentOperationException, CloudException { when(vm.getState()).thenReturn(vmDestroyedPrior ? VirtualMachine.State.Destroyed : VirtualMachine.State.Running); lenient().when(vm.getRemoved()).thenReturn(vmDestroyedPrior ? new Date() : null); Mockito.doNothing().when(accountManagerImpl).checkAccess(nullable(Account.class), Mockito.isNull(), nullable(Boolean.class), nullable(Account.class)); accountManagerImpl.deleteUserAccount(ACCOUNT_ID); return _usageEventDao.listAll(); } @Test // If the VM is already destroyed, no events should get emitted public void destroyedVMRootVolumeUsageEvent() throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException { lenient().doReturn(vm).when(_vmMgr).destroyVm(nullable(Long.class), nullable(Boolean.class)); List emittedEvents = deleteUserAccountRootVolumeUsageEvents(true); Assert.assertEquals(0, emittedEvents.size()); } @Ignore() @Test // If the VM is running, we should see one emitted event for the root // volume. public void runningVMRootVolumeUsageEvent() throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException { Mockito.doNothing().when(vmStatsDaoMock).removeAllByVmId(Mockito.anyLong()); Mockito.when(_vmMgr.destroyVm(nullable(Long.class), nullable(Boolean.class))).thenReturn(vm); List emittedEvents = deleteUserAccountRootVolumeUsageEvents(false); UsageEventVO event = emittedEvents.get(0); Assert.assertEquals(EventTypes.EVENT_VOLUME_DELETE, event.getType()); Assert.assertEquals(VOLUME_UUID, event.getResourceName()); } }