diff --git a/usage/pom.xml b/usage/pom.xml index 119f47d9d0b..1e78bc178f6 100644 --- a/usage/pom.xml +++ b/usage/pom.xml @@ -75,11 +75,6 @@ org.apache.maven.plugins maven-surefire-plugin - - - com/cloud/usage/UsageManagerTest.java - - org.apache.maven.plugins diff --git a/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java b/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java index 98b94e4c86e..9514ac04f2c 100644 --- a/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java +++ b/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java @@ -37,6 +37,7 @@ import org.apache.cloudstack.quota.QuotaAlertManager; import org.apache.cloudstack.quota.QuotaManager; import org.apache.cloudstack.quota.QuotaStatement; import org.apache.cloudstack.utils.usage.UsageUtils; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -990,7 +991,7 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna } else if (isNetworkOfferingEvent(eventType)) { createNetworkOfferingEvent(event); } else if (isVPNUserEvent(eventType)) { - createVPNUserEvent(event); + handleVpnUserEvent(event); } else if (isSecurityGroupEvent(eventType)) { createSecurityGroupEvent(event); } else if (isVmSnapshotEvent(eventType)) { @@ -1766,39 +1767,92 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna } } - private void createVPNUserEvent(UsageEventVO event) { - - long zoneId = 0L; - + /** + * Handles VPN user create and remove events: + * + * if the event received by this method is neither add nor remove, we ignore it. + */ + protected void handleVpnUserEvent(UsageEventVO event) { + long accountId = event.getAccountId(); + Account account = _accountDao.findByIdIncludingRemoved(accountId); + long zoneId = event.getZoneId(); long userId = event.getResourceId(); - if (EventTypes.EVENT_VPN_USER_ADD.equals(event.getType())) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Creating VPN user: " + userId + " for account: " + event.getAccountId()); - } - Account acct = _accountDao.findByIdIncludingRemoved(event.getAccountId()); - String userName = event.getResourceName(); - UsageVPNUserVO vpnUser = new UsageVPNUserVO(zoneId, event.getAccountId(), acct.getDomainId(), userId, userName, event.getCreateDate(), null); - _usageVPNUserDao.persist(vpnUser); - } else if (EventTypes.EVENT_VPN_USER_REMOVE.equals(event.getType())) { - SearchCriteria sc = _usageVPNUserDao.createSearchCriteria(); - sc.addAnd("accountId", SearchCriteria.Op.EQ, event.getAccountId()); - sc.addAnd("userId", SearchCriteria.Op.EQ, userId); - sc.addAnd("deleted", SearchCriteria.Op.NULL); - List vuVOs = _usageVPNUserDao.search(sc, null); - if (vuVOs.size() > 1) { - s_logger.warn("More that one usage entry for vpn user: " + userId + " assigned to account: " + event.getAccountId() + "; marking them all as deleted..."); - } - for (UsageVPNUserVO vuVO : vuVOs) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("deleting vpn user: " + vuVO.getUserId()); - } - vuVO.setDeleted(event.getCreateDate()); // there really shouldn't be more than one - _usageVPNUserDao.update(vuVO); - } + switch (event.getType()) { + case EventTypes.EVENT_VPN_USER_ADD: + createUsageVpnUser(event, account); + break; + case EventTypes.EVENT_VPN_USER_REMOVE: + deleteUsageVpnUser(event, account); + break; + default: + s_logger.debug(String.format("The event [type=%s, zoneId=%s, accountId=%s, userId=%s, resourceName=%s, createDate=%s] is neither of type [%s] nor [%s]", + event.getType(), zoneId, accountId, userId, event.getResourceName(), event.getCreateDate(), EventTypes.EVENT_VPN_USER_ADD, EventTypes.EVENT_VPN_USER_REMOVE)); } } + /** + * Find and delete, if exists, usage VPN user entries + */ + protected void deleteUsageVpnUser(UsageEventVO event, Account account) { + long accountId = account.getId(); + long userId = event.getResourceId(); + long zoneId = event.getZoneId(); + long domainId = account.getDomainId(); + + List usageVpnUsers = findUsageVpnUsers(accountId, zoneId, userId, domainId); + + if (CollectionUtils.isEmpty(usageVpnUsers)) { + s_logger.warn(String.format("No usage entry for vpn user [%s] assigned to account [%s] domain [%s] and zone [%s] was found.", + userId, accountId, domainId, zoneId)); + } + if (usageVpnUsers.size() > 1) { + s_logger.warn(String.format("More than one usage entry for vpn user [%s] assigned to account [%s] domain [%s] and zone [%s]; marking them all as deleted.", userId, + accountId, domainId, zoneId)); + } + for (UsageVPNUserVO vpnUser : usageVpnUsers) { + s_logger.debug(String.format("Deleting vpn user [%s] assigned to account [%s] domain [%s] and zone [%s] that was created at [%s].", vpnUser.getUserId(), + vpnUser.getAccountId(), vpnUser.getDomainId(), vpnUser.getZoneId(), vpnUser.getCreated())); + vpnUser.setDeleted(new Date()); + _usageVPNUserDao.update(vpnUser); + } + } + + /** + * Creates an entry for the Usage VPN User. + * If there is already an entry in the database with the same accountId, domainId, userId and zoneId, we do not persist a new entry. + */ + protected void createUsageVpnUser(UsageEventVO event, Account account) { + long accountId = account.getId(); + long userId = event.getResourceId(); + long zoneId = event.getZoneId(); + long domainId = account.getDomainId(); + + List usageVpnUsers = findUsageVpnUsers(accountId, zoneId, userId, domainId); + + if (usageVpnUsers.size() > 0) { + s_logger.debug(String.format("We do not need to create the usage VPN user [%s] assigned to account [%s] because it already exists.", userId, accountId)); + } else { + s_logger.debug(String.format("Creating VPN user user [%s] assigned to account [%s] domain [%s], zone [%s], and created at [%s]", userId, accountId, domainId, zoneId, + event.getCreateDate())); + UsageVPNUserVO vpnUser = new UsageVPNUserVO(zoneId, accountId, domainId, userId, event.getResourceName(), event.getCreateDate(), null); + _usageVPNUserDao.persist(vpnUser); + } + } + + protected List findUsageVpnUsers(long accountId, long zoneId, long userId, long domainId) { + SearchCriteria sc = _usageVPNUserDao.createSearchCriteria(); + sc.addAnd("zoneId", SearchCriteria.Op.EQ, zoneId); + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + sc.addAnd("userId", SearchCriteria.Op.EQ, userId); + sc.addAnd("deleted", SearchCriteria.Op.NULL); + return _usageVPNUserDao.search(sc, null); + } + private void createSecurityGroupEvent(UsageEventVO event) { long zoneId = -1L; diff --git a/usage/src/test/java/com/cloud/usage/UsageManagerImplTest.java b/usage/src/test/java/com/cloud/usage/UsageManagerImplTest.java new file mode 100644 index 00000000000..499d187e4ef --- /dev/null +++ b/usage/src/test/java/com/cloud/usage/UsageManagerImplTest.java @@ -0,0 +1,167 @@ +// 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.usage; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Before; +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 com.cloud.event.EventTypes; +import com.cloud.event.UsageEventVO; +import com.cloud.usage.dao.UsageVPNUserDao; +import com.cloud.user.AccountVO; +import com.cloud.user.dao.AccountDao; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class UsageManagerImplTest { + + @Spy + @InjectMocks + private UsageManagerImpl usageManagerImpl; + + @Mock + private UsageVPNUserDao usageVPNUserDaoMock; + + @Mock + private AccountDao accountDaoMock; + + @Mock + private UsageVPNUserVO vpnUserMock; + + @Mock + private AccountVO accountMock; + + @Mock + private UsageEventVO usageEventVOMock; + + private long accountMockId = 1l; + private long acountDomainIdMock = 2l; + + @Before + public void before() { + Mockito.when(accountMock.getId()).thenReturn(accountMockId); + Mockito.when(accountMock.getDomainId()).thenReturn(acountDomainIdMock); + + Mockito.doReturn(accountMock).when(accountDaoMock).findByIdIncludingRemoved(Mockito.anyLong()); + + } + + @Test + public void createUsageVpnUserTestUserExits() { + List vpnUsersMock = new ArrayList(); + vpnUsersMock.add(vpnUserMock); + + Mockito.doReturn(vpnUsersMock).when(usageManagerImpl).findUsageVpnUsers(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong()); + + usageManagerImpl.createUsageVpnUser(usageEventVOMock, accountMock); + + Mockito.verify(usageVPNUserDaoMock, Mockito.never()).persist(Mockito.any(UsageVPNUserVO.class)); + + } + + @Test + public void createUsageVpnUserTestUserDoesNotExits() { + List vpnUsersMock = new ArrayList(); + + Mockito.doReturn(vpnUsersMock).when(usageManagerImpl).findUsageVpnUsers(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong()); + Mockito.doReturn(vpnUserMock).when(usageVPNUserDaoMock).persist(Mockito.any(UsageVPNUserVO.class)); + + usageManagerImpl.createUsageVpnUser(usageEventVOMock, accountMock); + + Mockito.verify(usageVPNUserDaoMock, Mockito.times(1)).persist(Mockito.any(UsageVPNUserVO.class)); + + } + + @Test + public void deleteUsageVpnUserNoUserFound() { + List vpnUsersMock = new ArrayList(); + + Mockito.doReturn(vpnUsersMock).when(usageManagerImpl).findUsageVpnUsers(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong()); + + usageManagerImpl.deleteUsageVpnUser(usageEventVOMock, accountMock); + + Mockito.verify(usageVPNUserDaoMock, Mockito.never()).update(Mockito.any(UsageVPNUserVO.class)); + } + + @Test + public void deleteUsageVpnUserOneUserFound() { + List vpnUsersMock = new ArrayList(); + vpnUsersMock.add(vpnUserMock); + + Mockito.doReturn(vpnUsersMock).when(usageManagerImpl).findUsageVpnUsers(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong()); + Mockito.doNothing().when(usageVPNUserDaoMock).update(Mockito.any(UsageVPNUserVO.class)); + + usageManagerImpl.deleteUsageVpnUser(usageEventVOMock, accountMock); + + Mockito.verify(usageVPNUserDaoMock, Mockito.times(1)).update(Mockito.any(UsageVPNUserVO.class)); + } + + @Test + public void deleteUsageVpnUserMultipleUsersFound() { + List vpnUsersMock = new ArrayList(); + vpnUsersMock.add(vpnUserMock); + vpnUsersMock.add(Mockito.mock(UsageVPNUserVO.class)); + vpnUsersMock.add(Mockito.mock(UsageVPNUserVO.class)); + + Mockito.doReturn(vpnUsersMock).when(usageManagerImpl).findUsageVpnUsers(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong()); + Mockito.doNothing().when(usageVPNUserDaoMock).update(Mockito.any(UsageVPNUserVO.class)); + + usageManagerImpl.deleteUsageVpnUser(usageEventVOMock, accountMock); + + Mockito.verify(usageVPNUserDaoMock, Mockito.times(3)).update(Mockito.any(UsageVPNUserVO.class)); + } + + @Test + public void handleVpnUserEventTestAddUser() { + Mockito.when(this.usageEventVOMock.getType()).thenReturn(EventTypes.EVENT_VPN_USER_ADD); + Mockito.doNothing().when(this.usageManagerImpl).createUsageVpnUser(usageEventVOMock, accountMock); + + this.usageManagerImpl.handleVpnUserEvent(usageEventVOMock); + + Mockito.verify(usageManagerImpl).createUsageVpnUser(usageEventVOMock, accountMock); + Mockito.verify(usageManagerImpl, Mockito.never()).deleteUsageVpnUser(usageEventVOMock, accountMock); + } + + @Test + public void handleVpnUserEventTestRemoveUser() { + Mockito.when(this.usageEventVOMock.getType()).thenReturn(EventTypes.EVENT_VPN_USER_REMOVE); + Mockito.doNothing().when(this.usageManagerImpl).deleteUsageVpnUser(usageEventVOMock, accountMock); + + this.usageManagerImpl.handleVpnUserEvent(usageEventVOMock); + + Mockito.verify(usageManagerImpl, Mockito.never()).createUsageVpnUser(usageEventVOMock, accountMock); + Mockito.verify(usageManagerImpl).deleteUsageVpnUser(usageEventVOMock, accountMock); + } + + @Test + public void handleVpnUserEventTestEventIsNeitherAddNorRemove() { + Mockito.when(this.usageEventVOMock.getType()).thenReturn("VPN.USER.UPDATE"); + + this.usageManagerImpl.handleVpnUserEvent(usageEventVOMock); + + Mockito.verify(usageManagerImpl, Mockito.never()).createUsageVpnUser(usageEventVOMock,accountMock); + Mockito.verify(usageManagerImpl, Mockito.never()).deleteUsageVpnUser(usageEventVOMock, accountMock); + } +} \ No newline at end of file diff --git a/usage/src/test/java/com/cloud/usage/UsageManagerTest.java b/usage/src/test/java/com/cloud/usage/UsageManagerTest.java deleted file mode 100644 index 139b65d42db..00000000000 --- a/usage/src/test/java/com/cloud/usage/UsageManagerTest.java +++ /dev/null @@ -1,113 +0,0 @@ -// 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.usage; - -import java.util.Date; - -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import junit.framework.TestCase; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import com.cloud.usage.parser.IPAddressUsageParser; -import com.cloud.usage.parser.LoadBalancerUsageParser; -import com.cloud.usage.parser.NetworkOfferingUsageParser; -import com.cloud.usage.parser.NetworkUsageParser; -import com.cloud.usage.parser.PortForwardingUsageParser; -import com.cloud.usage.parser.SecurityGroupUsageParser; -import com.cloud.usage.parser.StorageUsageParser; -import com.cloud.usage.parser.VMInstanceUsageParser; -import com.cloud.usage.parser.VPNUserUsageParser; -import com.cloud.usage.parser.VmDiskUsageParser; -import com.cloud.usage.parser.VolumeUsageParser; -import com.cloud.user.AccountVO; -import com.cloud.utils.component.ComponentContext; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = "classpath:/UsageManagerTestContext.xml") -public class UsageManagerTest extends TestCase { - @Inject - UsageManagerImpl _usageMgr = null; - @Inject - VMInstanceUsageParser vmParser = null; - @Inject - IPAddressUsageParser ipParser = null; - @Inject - LoadBalancerUsageParser lbParser = null; - @Inject - NetworkOfferingUsageParser noParser = null; - @Inject - NetworkUsageParser netParser = null; - @Inject - VmDiskUsageParser vmdiskParser = null; - @Inject - PortForwardingUsageParser pfParser = null; - @Inject - SecurityGroupUsageParser sgParser = null; - @Inject - StorageUsageParser stParser = null; - @Inject - VolumeUsageParser volParser = null; - @Inject - VPNUserUsageParser vpnParser = null; - - Date startDate = null; - Date endDate = null; - - @Before - public void setup() throws Exception { - System.setProperty("pid", "5678"); - ComponentContext.initComponentsLifeCycle(); - startDate = new Date(); - endDate = new Date(100000L + System.currentTimeMillis()); - } - - @Test - public void testParse() throws ConfigurationException { - UsageJobVO job = new UsageJobVO(); - _usageMgr.parse(job, System.currentTimeMillis(), 100000L + System.currentTimeMillis()); - } - - @Test - public void testSchedule() throws ConfigurationException { - _usageMgr.scheduleParse(); - } - - @Test - public void testParsers() throws ConfigurationException { - AccountVO account = new AccountVO(); - account.setId(2L); - VMInstanceUsageParser.parse(account, startDate, endDate); - IPAddressUsageParser.parse(account, startDate, endDate); - LoadBalancerUsageParser.parse(account, startDate, endDate); - NetworkOfferingUsageParser.parse(account, startDate, endDate); - NetworkUsageParser.parse(account, startDate, endDate); - VmDiskUsageParser.parse(account, startDate, endDate); - PortForwardingUsageParser.parse(account, startDate, endDate); - SecurityGroupUsageParser.parse(account, startDate, endDate); - StorageUsageParser.parse(account, startDate, endDate); - VolumeUsageParser.parse(account, startDate, endDate); - VPNUserUsageParser.parse(account, startDate, endDate); - } - -}