From 9a3a67aae3967a979739a03d42f0a105b2b3cf5e Mon Sep 17 00:00:00 2001 From: GabrielBrascher Date: Fri, 8 Mar 2019 17:00:19 -0300 Subject: [PATCH 1/5] the java application for the cloudstack-usage.service was retrieving '$$'; thus, the _pid variable received '$$', causing an exception. --- packaging/systemd/cloudstack-usage.default | 12 ++++- packaging/systemd/cloudstack-usage.service | 4 +- .../com/cloud/usage/UsageManagerImpl.java | 44 ++++++++++++++++--- .../java/com/cloud/usage/UsageServer.java | 6 +-- 4 files changed, 53 insertions(+), 13 deletions(-) diff --git a/packaging/systemd/cloudstack-usage.default b/packaging/systemd/cloudstack-usage.default index 26f552859f37..77483d0411f1 100644 --- a/packaging/systemd/cloudstack-usage.default +++ b/packaging/systemd/cloudstack-usage.default @@ -15,8 +15,18 @@ # specific language governing permissions and limitations # under the License. -JAVA_OPTS="-Dpid=$$ -Xms256m -Xmx2048m" +JAVA_OPTS="-Xms256m -Xmx2048m" CLASSPATH="/usr/share/cloudstack-usage/*:/usr/share/cloudstack-usage/lib/*:/usr/share/cloudstack-mysql-ha/lib/*:/etc/cloudstack/usage:/usr/share/java/mysql-connector-java.jar" JAVA_CLASS=com.cloud.usage.UsageServer + +################################################################################################ +#You can uncomment one of these options if you want to enable Java remote debugging. # +#You can change the parameters at your will. The 'address' field defines the port to be used. # +################################################################################################ +# This option here should be used with 'systemmd' based operating systems such as CentOS7, Ubuntu 16, and so on. +#JAVA_DEBUG="-agentlib:jdwp=transport=dt_socket,address=8001,server=y,suspend=n" + +# On the other hand, this option is used by CentOS6. +#JAVA_DEBUG="-Xrunjdwp:transport=dt_socket,address=8001,server=y,suspend=n" diff --git a/packaging/systemd/cloudstack-usage.service b/packaging/systemd/cloudstack-usage.service index f8874867c69a..ad97788bd639 100644 --- a/packaging/systemd/cloudstack-usage.service +++ b/packaging/systemd/cloudstack-usage.service @@ -24,7 +24,9 @@ After=network.target network-online.target [Service] Type=simple EnvironmentFile=/etc/default/cloudstack-usage -ExecStart=/usr/bin/java $JAVA_OPTS -cp $CLASSPATH $JAVA_CLASS +ExecStart=/usr/bin/java $JAVA_DEBUG $JAVA_OPTS -cp $CLASSPATH $JAVA_CLASS +ExecStartPost=/bin/sh -c "systemctl show -p MainPID cloudstack-usage.service 2>/dev/null | cut -d= -f2 > /etc/cloudstack/usage/cloudstack-usage.service.pid" + Restart=always RestartSec=10s diff --git a/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java b/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java index d70910249b2f..367cd6da0c61 100644 --- a/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java +++ b/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java @@ -16,7 +16,10 @@ // under the License. package com.cloud.usage; +import java.io.File; +import java.io.IOException; import java.net.InetAddress; +import java.nio.charset.Charset; import java.sql.SQLException; import java.util.ArrayList; import java.util.Calendar; @@ -33,15 +36,17 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.quota.QuotaAlertManager; import org.apache.cloudstack.quota.QuotaManager; import org.apache.cloudstack.quota.QuotaStatement; +import org.apache.cloudstack.usage.UsageTypes; import org.apache.cloudstack.utils.usage.UsageUtils; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.math.NumberUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.managed.context.ManagedContextRunnable; -import org.apache.cloudstack.usage.UsageTypes; import com.cloud.alert.AlertManager; import com.cloud.event.EventTypes; @@ -57,10 +62,10 @@ import com.cloud.usage.dao.UsageNetworkOfferingDao; import com.cloud.usage.dao.UsagePortForwardingRuleDao; import com.cloud.usage.dao.UsageSecurityGroupDao; -import com.cloud.usage.dao.UsageVMSnapshotOnPrimaryDao; import com.cloud.usage.dao.UsageStorageDao; import com.cloud.usage.dao.UsageVMInstanceDao; import com.cloud.usage.dao.UsageVMSnapshotDao; +import com.cloud.usage.dao.UsageVMSnapshotOnPrimaryDao; import com.cloud.usage.dao.UsageVPNUserDao; import com.cloud.usage.dao.UsageVmDiskDao; import com.cloud.usage.dao.UsageVolumeDao; @@ -72,11 +77,11 @@ import com.cloud.usage.parser.SecurityGroupUsageParser; import com.cloud.usage.parser.StorageUsageParser; import com.cloud.usage.parser.VMInstanceUsageParser; +import com.cloud.usage.parser.VMSanpshotOnPrimaryParser; import com.cloud.usage.parser.VMSnapshotUsageParser; import com.cloud.usage.parser.VPNUserUsageParser; import com.cloud.usage.parser.VmDiskUsageParser; import com.cloud.usage.parser.VolumeUsageParser; -import com.cloud.usage.parser.VMSanpshotOnPrimaryParser; import com.cloud.user.Account; import com.cloud.user.AccountVO; import com.cloud.user.UserStatisticsVO; @@ -92,6 +97,7 @@ import com.cloud.utils.db.QueryBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.TransactionLegacy; +import com.cloud.utils.exception.CloudRuntimeException; @Component public class UsageManagerImpl extends ManagerBase implements UsageManager, Runnable { @@ -176,6 +182,11 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna private Future _sanity = null; private boolean usageSnapshotSelection = false; + /** + * File that stores a string corresponding to the cloudstack-usage.service process id (pid). + */ + private static final String CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE = "/etc/cloudstack/usage/cloudstack-usage.service.pid"; + public UsageManagerImpl() { } @@ -271,10 +282,31 @@ public boolean configure(String name, Map params) throws Configu s_logger.error("Unhandled exception configuring UsageManger", e); throw new ConfigurationException("Unhandled exception configuring UsageManager " + e.toString()); } - _pid = Integer.parseInt(System.getProperty("pid")); + + configureUsageManagerServicePid(); return true; } + /** + * Sets the '_pid' variable based on the cloudstack-usage.service process id (pid). + */ + protected void configureUsageManagerServicePid() { + File usageServicePid = new File(CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE); + if (!usageServicePid.exists()) { + throw new CloudRuntimeException(String.format("Cannot find file [%s].", CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE)); + } + if (!usageServicePid.canRead()) { + throw new CloudRuntimeException(String.format("Cannot read file [%s].", CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE)); + } + try { + String pidAsString = FileUtils.readFileToString(usageServicePid, Charset.defaultCharset()); + String pidAsStringWithoutLineSeparator = pidAsString.replace(System.getProperty("line.separator"), ""); + _pid = NumberUtils.toInt(pidAsStringWithoutLineSeparator); + } catch (IOException e) { + throw new CloudRuntimeException(e); + } + } + @Override public boolean start() { if (s_logger.isInfoEnabled()) { diff --git a/usage/src/main/java/com/cloud/usage/UsageServer.java b/usage/src/main/java/com/cloud/usage/UsageServer.java index df3f374cc308..5e8a69d17cb2 100644 --- a/usage/src/main/java/com/cloud/usage/UsageServer.java +++ b/usage/src/main/java/com/cloud/usage/UsageServer.java @@ -51,11 +51,7 @@ public void start() { appContext = new ClassPathXmlApplicationContext("usageApplicationContext.xml"); - try { - ComponentContext.initComponentsLifeCycle(); - } catch (Exception e) { - e.printStackTrace(); - } + ComponentContext.initComponentsLifeCycle(); mgr = appContext.getBean(UsageManager.class); From 353251b1bad56f6107abdab8e86987da58b1a104 Mon Sep 17 00:00:00 2001 From: GabrielBrascher Date: Mon, 11 Mar 2019 10:03:17 -0300 Subject: [PATCH 2/5] Change pid file to /var/run/cloudstack-usage.service.pid and throw exception in case of null or blank pid (NumberUtils.toInt returns zero if the conversion fails). --- packaging/systemd/cloudstack-usage.service | 2 +- .../java/com/cloud/usage/UsageManagerImpl.java | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packaging/systemd/cloudstack-usage.service b/packaging/systemd/cloudstack-usage.service index ad97788bd639..f7313a8fc139 100644 --- a/packaging/systemd/cloudstack-usage.service +++ b/packaging/systemd/cloudstack-usage.service @@ -25,7 +25,7 @@ After=network.target network-online.target Type=simple EnvironmentFile=/etc/default/cloudstack-usage ExecStart=/usr/bin/java $JAVA_DEBUG $JAVA_OPTS -cp $CLASSPATH $JAVA_CLASS -ExecStartPost=/bin/sh -c "systemctl show -p MainPID cloudstack-usage.service 2>/dev/null | cut -d= -f2 > /etc/cloudstack/usage/cloudstack-usage.service.pid" +ExecStartPost=/bin/sh -c "systemctl show -p MainPID cloudstack-usage.service 2>/dev/null | cut -d= -f2 > /var/run/cloudstack-usage.service.pid" Restart=always RestartSec=10s diff --git a/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java b/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java index 367cd6da0c61..f77aa5cc4456 100644 --- a/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java +++ b/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java @@ -183,9 +183,9 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna private boolean usageSnapshotSelection = false; /** - * File that stores a string corresponding to the cloudstack-usage.service process id (pid). + * File "/var/run/cloudstack-usage.service.pid" that stores a string corresponding to the cloudstack-usage.service process id (pid). */ - private static final String CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE = "/etc/cloudstack/usage/cloudstack-usage.service.pid"; + private static final String CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE = "/var/run/cloudstack-usage.service.pid"; public UsageManagerImpl() { } @@ -288,7 +288,13 @@ public boolean configure(String name, Map params) throws Configu } /** - * Sets the '_pid' variable based on the cloudstack-usage.service process id (pid). + * Sets the '_pid' variable based on the cloudstack-usage.service process id (pid) according to the file /var/run/cloudstack-usage.service.pid.
+ * It thorws a CloudRuntimeException in the following cases: + *
    + *
  • Cannot find the pid file
  • + *
  • Cannot read the pid file
  • + *
  • NumberUtils.toInt returns 0 (zero) if the conversion fails (pid is null or "")
  • + *
*/ protected void configureUsageManagerServicePid() { File usageServicePid = new File(CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE); @@ -302,6 +308,10 @@ protected void configureUsageManagerServicePid() { String pidAsString = FileUtils.readFileToString(usageServicePid, Charset.defaultCharset()); String pidAsStringWithoutLineSeparator = pidAsString.replace(System.getProperty("line.separator"), ""); _pid = NumberUtils.toInt(pidAsStringWithoutLineSeparator); + if (_pid == 0) { + throw new CloudRuntimeException( + String.format("Failed to retrieve a valid cloudstack-usage.service pid [file:%s, pid at file:%s]", CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE, pidAsString)); + } } catch (IOException e) { throw new CloudRuntimeException(e); } From 4c948e0853733dbad1cbd80fe17c6debc0e65d09 Mon Sep 17 00:00:00 2001 From: GabrielBrascher Date: Mon, 11 Mar 2019 10:47:52 -0300 Subject: [PATCH 3/5] Fix typo --- usage/src/main/java/com/cloud/usage/UsageManagerImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java b/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java index f77aa5cc4456..9f426eed23b8 100644 --- a/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java +++ b/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java @@ -289,11 +289,11 @@ public boolean configure(String name, Map params) throws Configu /** * Sets the '_pid' variable based on the cloudstack-usage.service process id (pid) according to the file /var/run/cloudstack-usage.service.pid.
- * It thorws a CloudRuntimeException in the following cases: + * It throws a CloudRuntimeException in the following cases: *
    *
  • Cannot find the pid file
  • *
  • Cannot read the pid file
  • - *
  • NumberUtils.toInt returns 0 (zero) if the conversion fails (pid is null or "")
  • + *
  • NumberUtils.toInt returns 0 (zero) if the conversion fails (pid is null or "")
  • *
*/ protected void configureUsageManagerServicePid() { From 7a5649ecfc1a6347740de7c923536c19c2f7a2b2 Mon Sep 17 00:00:00 2001 From: GabrielBrascher Date: Mon, 11 Mar 2019 13:52:02 -0300 Subject: [PATCH 4/5] Removing tests that are not runned by maven and have no asserts --- .../com/cloud/usage/UsageManagerTest.java | 113 ------------------ .../resources/UsageManagerTestContext.xml | 42 ------- 2 files changed, 155 deletions(-) delete mode 100644 usage/src/test/java/com/cloud/usage/UsageManagerTest.java delete mode 100644 usage/src/test/resources/UsageManagerTestContext.xml 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 139b65d42dba..000000000000 --- 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); - } - -} diff --git a/usage/src/test/resources/UsageManagerTestContext.xml b/usage/src/test/resources/UsageManagerTestContext.xml deleted file mode 100644 index 152de68a5802..000000000000 --- a/usage/src/test/resources/UsageManagerTestContext.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - From a42bc9fd7f7473bce7080e3e532578ab6295fecd Mon Sep 17 00:00:00 2001 From: GabrielBrascher Date: Mon, 11 Mar 2019 15:44:25 -0300 Subject: [PATCH 5/5] Add unit test for UsageManagerImpl.configureUsageManagerServicePid() --- .../com/cloud/usage/UsageManagerImpl.java | 21 ++--- .../com/cloud/usage/UsageManagerImplTest.java | 84 +++++++++++++++++++ 2 files changed, 95 insertions(+), 10 deletions(-) create mode 100644 usage/src/test/java/com/cloud/usage/UsageManagerImplTest.java diff --git a/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java b/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java index 9f426eed23b8..ed32a0315772 100644 --- a/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java +++ b/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java @@ -183,7 +183,7 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna private boolean usageSnapshotSelection = false; /** - * File "/var/run/cloudstack-usage.service.pid" that stores a string corresponding to the cloudstack-usage.service process id (pid). + * File "/var/run/cloudstack-usage.service.pid" that stores a string corresponding to the cloudstack-usage.service process identified (PID). */ private static final String CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE = "/var/run/cloudstack-usage.service.pid"; @@ -283,20 +283,20 @@ public boolean configure(String name, Map params) throws Configu throw new ConfigurationException("Unhandled exception configuring UsageManager " + e.toString()); } - configureUsageManagerServicePid(); + _pid = retrieveUsageManagerServicePid(); return true; } /** - * Sets the '_pid' variable based on the cloudstack-usage.service process id (pid) according to the file /var/run/cloudstack-usage.service.pid.
+ * Retrieves the cloudstack-usage.service PID according to the file /var/run/cloudstack-usage.service.pid.
* It throws a CloudRuntimeException in the following cases: *
    - *
  • Cannot find the pid file
  • - *
  • Cannot read the pid file
  • - *
  • NumberUtils.toInt returns 0 (zero) if the conversion fails (pid is null or "")
  • + *
  • Cannot find the PID file
  • + *
  • Cannot read the PID file
  • + *
  • NumberUtils.toInt returns 0 (zero) if the conversion fails (PID is null or "")
  • *
*/ - protected void configureUsageManagerServicePid() { + protected int retrieveUsageManagerServicePid() { File usageServicePid = new File(CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE); if (!usageServicePid.exists()) { throw new CloudRuntimeException(String.format("Cannot find file [%s].", CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE)); @@ -306,12 +306,13 @@ protected void configureUsageManagerServicePid() { } try { String pidAsString = FileUtils.readFileToString(usageServicePid, Charset.defaultCharset()); - String pidAsStringWithoutLineSeparator = pidAsString.replace(System.getProperty("line.separator"), ""); - _pid = NumberUtils.toInt(pidAsStringWithoutLineSeparator); - if (_pid == 0) { + String pidAsStringWithoutLineSeparator = pidAsString.trim(); + int pid = NumberUtils.toInt(pidAsStringWithoutLineSeparator); + if (pid == 0) { throw new CloudRuntimeException( String.format("Failed to retrieve a valid cloudstack-usage.service pid [file:%s, pid at file:%s]", CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE, pidAsString)); } + return pid; } catch (IOException e) { throw new CloudRuntimeException(e); } 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 000000000000..07b09d2c78fc --- /dev/null +++ b/usage/src/test/java/com/cloud/usage/UsageManagerImplTest.java @@ -0,0 +1,84 @@ +// 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 +// 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.io.File; +import java.io.IOException; +import java.nio.charset.Charset; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.cloud.utils.exception.CloudRuntimeException; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({FileUtils.class, UsageManagerImpl.class, NumberUtils.class}) +public class UsageManagerImplTest { + + private static final String CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE = "/var/run/cloudstack-usage.service.pid"; + private UsageManagerImpl usageManagerImpl = new UsageManagerImpl(); + + @Test + public void retrieveUsageManagerServicePidTestCompleteExecutionFlow() throws Exception { + prepareAndVerifyTestRetrieveUsageManagerServicePidTest(true, true, 1, 1234, "1234" + System.getProperty("line.separator")); + } + + @Test(expected=CloudRuntimeException.class) + public void retrieveUsageManagerServicePidTestFileDoesNotExist() throws Exception { + prepareAndVerifyTestRetrieveUsageManagerServicePidTest(false, true, 0, 1234, "1234" + System.getProperty("line.separator")); + } + + @Test(expected = CloudRuntimeException.class) + public void retrieveUsageManagerServicePidTestCannotReadFile() throws Exception { + prepareAndVerifyTestRetrieveUsageManagerServicePidTest(true, false, 1, 1234, "1234" + System.getProperty("line.separator")); + } + + @Test(expected = CloudRuntimeException.class) + public void retrieveUsageManagerServicePidTestPidEqualsToZero() throws Exception { + prepareAndVerifyTestRetrieveUsageManagerServicePidTest(true, true, 1, 0, "abc"); + } + + private void prepareAndVerifyTestRetrieveUsageManagerServicePidTest(boolean fileExists, boolean canReadFile, int timesCanReadIsExecuted, int expectedPid, + String readedStringFromFile) + throws Exception, IOException { + File usageServicePid = Mockito.mock(File.class); + PowerMockito.whenNew(File.class).withArguments(CLOUDSTACK_USAGE_SERVER_SERVICE_PID_FILE).thenReturn(usageServicePid); + + Mockito.when(usageServicePid.exists()).thenReturn(fileExists); + Mockito.when(usageServicePid.canRead()).thenReturn(canReadFile); + + PowerMockito.mockStatic(FileUtils.class); + Mockito.when(FileUtils.readFileToString(usageServicePid, Charset.defaultCharset())).thenReturn(readedStringFromFile); + + int result = usageManagerImpl.retrieveUsageManagerServicePid(); + + InOrder inOrder = Mockito.inOrder(usageServicePid); + inOrder.verify(usageServicePid).exists(); + inOrder.verify(usageServicePid, Mockito.times(timesCanReadIsExecuted)).canRead(); + + Assert.assertEquals(expectedPid, result); + } + +}