Author: ghenzler
Date: Fri Jan  4 14:48:42 2019
New Revision: 1850371

URL: http://svn.apache.org/viewvc?rev=1850371&view=rev
Log:
FELIX-6012 Introduce module "generalchecks" with basic general purpose checks

Added:
    felix/trunk/healthcheck/generalchecks/
    felix/trunk/healthcheck/generalchecks/bnd.bnd
    felix/trunk/healthcheck/generalchecks/pom.xml   (with props)
    felix/trunk/healthcheck/generalchecks/src/
    felix/trunk/healthcheck/generalchecks/src/main/
    felix/trunk/healthcheck/generalchecks/src/main/java/
    felix/trunk/healthcheck/generalchecks/src/main/java/org/
    felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/
    felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/
    felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/
    
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/
    
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/BundlesStartedCheck.java
   (with props)
    
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/CpuCheck.java
   (with props)
    
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/DiskSpaceCheck.java
   (with props)
    
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/MemoryCheck.java
   (with props)
    
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/ThreadUsageCheck.java
   (with props)
    
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/
    
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/UnitsUtil.java
   (with props)
    felix/trunk/healthcheck/generalchecks/src/test/
    felix/trunk/healthcheck/generalchecks/src/test/java/
    felix/trunk/healthcheck/generalchecks/src/test/java/org/
    felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/
    felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/
    felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/
    
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/
    
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/
    
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/UnitsUtilTest.java
   (with props)

Added: felix/trunk/healthcheck/generalchecks/bnd.bnd
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/bnd.bnd?rev=1850371&view=auto
==============================================================================
--- felix/trunk/healthcheck/generalchecks/bnd.bnd (added)
+++ felix/trunk/healthcheck/generalchecks/bnd.bnd Fri Jan  4 14:48:42 2019
@@ -0,0 +1,9 @@
+Bundle-Category: healthcheck
+
+Bundle-Description: ${project.description}
+
+Bundle-DocURL: https://felix.apache.org
+
+Bundle-License: Apache License, Version 2.0
+
+Bundle-Vendor: The Apache Software Foundation

Added: felix/trunk/healthcheck/generalchecks/pom.xml
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/pom.xml?rev=1850371&view=auto
==============================================================================
--- felix/trunk/healthcheck/generalchecks/pom.xml (added)
+++ felix/trunk/healthcheck/generalchecks/pom.xml Fri Jan  4 14:48:42 2019
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>felix-parent</artifactId>
+        <version>6</version>
+        <relativePath/>
+    </parent>
+
+    <artifactId>org.apache.felix.healthcheck.generalchecks</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+
+    <name>Apache Felix Health Check :: General Checks</name>
+    <inceptionYear>2013</inceptionYear>
+
+    <description>
+        General purpose health checks that can be simply configured to check 
for generic aspects like disk space, started bundles, remote service 
availability, etc.
+    </description>
+
+    <scm>
+        
<connection>scm:svn:http://svn.apache.org/repos/asf/felix/trunk/healthcheck/genericchecks</connection>
+        
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/felix/trunk/healthcheck/genericchecks</developerConnection>
+        <url>http://svn.apache.org/viewvc/felix/trunk/http/genericchecks/</url>
+    </scm>
+
+    <build>
+        <plugins>
+
+            <plugin>
+                <groupId>biz.aQute.bnd</groupId>
+                <artifactId>bnd-maven-plugin</artifactId>
+                <version>4.1.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>bnd-process</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>biz.aQute.bnd</groupId>
+                <artifactId>bnd-baseline-maven-plugin</artifactId>
+                <version>4.1.0</version>
+            </plugin>
+
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.core</artifactId>
+            <version>6.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.cmpn</artifactId>
+            <version>6.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.healthcheck.api</artifactId>
+            <version>2.0.0-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.healthcheck.annotation</artifactId>
+            <version>2.0.0-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.7.6</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.4</version>
+            <scope>provided</scope>
+        </dependency>
+   
+        <!-- START test scope dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.12</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>1.9.5</version>
+            <scope>test</scope>
+        </dependency>
+        <!-- END test scope dependencies -->
+
+    </dependencies>
+</project>

Propchange: felix/trunk/healthcheck/generalchecks/pom.xml
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/BundlesStartedCheck.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/BundlesStartedCheck.java?rev=1850371&view=auto
==============================================================================
--- 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/BundlesStartedCheck.java
 (added)
+++ 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/BundlesStartedCheck.java
 Fri Jan  4 14:48:42 2019
@@ -0,0 +1,163 @@
+/*
+ * 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 SF 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 org.apache.felix.hc.generalchecks;
+
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.felix.hc.annotation.HealthCheckService;
+import org.apache.felix.hc.api.HealthCheck;
+import org.apache.felix.hc.api.Result;
+import org.apache.felix.hc.util.FormattingResultLog;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@HealthCheckService(name = BundlesStartedCheck.HC_NAME)
+@Component(configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = BundlesStartedCheck.Config.class, factory = true)
+public class BundlesStartedCheck implements HealthCheck {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(BundlesStartedCheck.class);
+
+    public static final String HC_NAME = "Bundles Started";
+    public static final String HC_LABEL = "Health Check: " + HC_NAME;
+
+    @ObjectClassDefinition(name = HC_LABEL, description = "Checks the 
configured path(s) against the given thresholds")
+    public @interface Config {
+        @AttributeDefinition(name = "Name", description = "Name of this health 
check")
+        String hc_name() default HC_NAME;
+
+        @AttributeDefinition(name = "Tags", description = "List of tags for 
this health check, used to select subsets of health checks for execution e.g. 
by a composite health check.")
+        String[] hc_tags() default {};
+
+        @AttributeDefinition(name = "Includes RegEx", description = "RegEx to 
select all relevant bundles for this check")
+        String includesRegex() default ".*";
+
+        @AttributeDefinition(name = "Excludes RegEx", description = "Optional 
RegEx to exclude bundles from this check")
+        String excludesRegex() default "";
+
+        @AttributeDefinition(name = "CRITICAL for inactive bundles", 
description = "By default inactive bundles produce warnings, if this is set to 
true inactive bundles produce a CRITICAL result")
+        boolean useCriticalForInactive() default false;
+        
+        @AttributeDefinition
+        String webconsole_configurationFactory_nameHint() default "Bundles 
started includes: {includesRegex} excludes: {excludesRegex}";
+    }
+
+    private BundleContext bundleContext;
+    private Pattern includesRegex;
+    private Pattern excludesRegex;
+    boolean useCriticalForInactive;
+
+    @Activate
+    protected void activate(BundleContext bundleContext, Config config) {
+        this.bundleContext = bundleContext;
+        this.includesRegex = Pattern.compile(config.includesRegex());
+        this.excludesRegex = StringUtils.isNotBlank(config.excludesRegex()) ? 
Pattern.compile(config.excludesRegex()) : null;
+        this.useCriticalForInactive = config.useCriticalForInactive();
+        LOG.info("Activated bundles started HC for includesRegex={} 
excludesRegex={}% useCriticalForInactive={}", includesRegex, excludesRegex, 
useCriticalForInactive);
+    }
+
+    
+    @Override
+    public Result execute() {
+        FormattingResultLog log = new FormattingResultLog();
+
+        Bundle[] bundles = this.bundleContext.getBundles();
+        log.debug("Framwork has {} bundles in total", bundles.length);
+ 
+        int countExcluded = 0;
+        int relevantBundlesCount = 0;
+        int inctiveCount = 0;
+        for (Bundle bundle : bundles) {
+            String bundleSymbolicName = bundle.getSymbolicName();
+            int bundleState = bundle.getState();
+            
+            if(!includesRegex.matcher(bundleSymbolicName).matches()) {
+                LOG.debug("Bundle {} not matched by {}", bundleSymbolicName, 
includesRegex);
+                continue;
+            }
+
+            if(excludesRegex!=null && 
excludesRegex.matcher(bundleSymbolicName).matches()) {
+                LOG.debug("Bundle {} excluded {}", bundleSymbolicName, 
excludesRegex);
+                countExcluded ++;
+                continue;
+            }
+            relevantBundlesCount++;
+            
+            boolean bundleIsLogged = false;
+            if (bundleState != Bundle.ACTIVE) {
+                // support lazy activation 
(https://www.osgi.org/developer/design/lazy-start/)
+                if (bundleState == Bundle.STARTING && 
isLazyActivation(bundle)) {
+                    LOG.debug("Ignoring lazily activated bundle {}", 
bundleSymbolicName);
+                } else  if (StringUtils.isNotBlank((String) 
bundle.getHeaders().get(Constants.FRAGMENT_HOST))) {
+                    LOG.debug("Ignoring bundle fragment: {}", 
bundleSymbolicName);
+                } else {
+                    String msg = "Inactive bundle {} {}: {}";
+                    Object[] msgObjs = new Object[] {bundle.getBundleId(), 
bundleSymbolicName, getStateLabel(bundleState)};
+                    LOG.debug(msg, msgObjs);
+                    if(useCriticalForInactive) {
+                        log.critical(msg, msgObjs);
+                    } else {
+                        log.warn(msg, msgObjs);
+                    }
+                    bundleIsLogged = true;
+                    inctiveCount++;
+                }
+            }
+            if(!bundleIsLogged) {
+                log.debug("Bundle {} {}: {}", bundle.getBundleId(), 
bundleSymbolicName, getStateLabel(bundleState));
+            }
+        }
+        
+        String baseMsg = relevantBundlesCount+" 
bundles"+(!includesRegex.pattern().equals(".*")?" for pattern 
"+includesRegex.pattern(): "");
+        String excludedMsg = countExcluded > 0 ? " (" + countExcluded + " 
excluded via pattern "+excludesRegex.pattern()+")" : "";
+        if (inctiveCount > 0) {
+            log.info("Found  "+inctiveCount + " inactive of "+baseMsg + 
excludedMsg);
+        } else {
+            log.info("All "+baseMsg+" are started" + excludedMsg);
+        }
+
+        return new Result(log);
+    }
+
+    private static boolean isLazyActivation(Bundle b) {
+        return 
Constants.ACTIVATION_LAZY.equals(b.getHeaders().get(Constants.BUNDLE_ACTIVATIONPOLICY));
+    }
+    
+    private static String getStateLabel(int state) {
+        switch(state) {
+        case Bundle.UNINSTALLED: return "UNINSTALLED";
+        case Bundle.INSTALLED: return "INSTALLED";
+        case Bundle.RESOLVED: return "RESOLVED";
+        case Bundle.STARTING: return "STARTING";
+        case Bundle.STOPPING: return "STOPPING";
+        case Bundle.ACTIVE: return "ACTIVE";
+        default: return ""+state;
+        }
+    } 
+
+}

Propchange: 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/BundlesStartedCheck.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/CpuCheck.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/CpuCheck.java?rev=1850371&view=auto
==============================================================================
--- 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/CpuCheck.java
 (added)
+++ 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/CpuCheck.java
 Fri Jan  4 14:48:42 2019
@@ -0,0 +1,118 @@
+/*
+ * 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 SF 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 org.apache.felix.hc.generalchecks;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+
+import org.apache.felix.hc.annotation.HealthCheckService;
+import org.apache.felix.hc.api.HealthCheck;
+import org.apache.felix.hc.api.Result;
+import org.apache.felix.hc.api.ResultLog;
+import org.apache.felix.hc.util.FormattingResultLog;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@HealthCheckService(name = CpuCheck.HC_NAME)
+@Component(configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = CpuCheck.Config.class, factory = false)
+public class CpuCheck implements HealthCheck {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CpuCheck.class);
+
+    public static final String HC_NAME = "CPU";
+    public static final String HC_LABEL = "Health Check: " + HC_NAME;
+
+    @ObjectClassDefinition(name = HC_LABEL, description = "Checks for high CPU 
load")
+    public @interface Config {
+        @AttributeDefinition(name = "Name", description = "Name of this health 
check")
+        String hc_name() default HC_NAME;
+
+        @AttributeDefinition(name = "Tags", description = "List of tags for 
this health check, used to select subsets of health checks for execution e.g. 
by a composite health check.")
+        String[] hc_tags() default {};
+
+        @AttributeDefinition(name = "Disk used threshold for WARN", 
description = "in percent, if disk usage is over this limit the result is WARN")
+        long cpuPercentageThresholdWarn() default 95;
+
+    }
+
+    private long cpuPercentageThresholdWarn;
+
+    @Activate
+    protected void activate(final Config config) {
+        cpuPercentageThresholdWarn = config.cpuPercentageThresholdWarn();
+        LOG.info("Activated CPU HC: cpuPercentageThresholdWarn={}%", 
cpuPercentageThresholdWarn);
+    }
+
+    @Override
+    public Result execute() {
+
+        FormattingResultLog log = new FormattingResultLog();
+
+        double processCpuLoad = Double.NaN;
+        try {
+            processCpuLoad = getProcessCpuLoad();
+        } catch (Exception e) {
+            log.add(new ResultLog.Entry(Result.Status.HEALTH_CHECK_ERROR, 
"Could not get process CPU load: " + e, e));
+        }
+
+        if (Double.isNaN(processCpuLoad)) {
+            log.info("No CPU load available yet");
+        } else {
+            String loadStr = String.format("%.1f", processCpuLoad);
+            Result.Status status = processCpuLoad < cpuPercentageThresholdWarn 
? Result.Status.OK : Result.Status.WARN;
+            log.add(new ResultLog.Entry(status, "Process CPU Usage: " + 
loadStr + "%"));
+        }
+        return new Result(log);
+
+    }
+
+    public double getProcessCpuLoad() throws MalformedObjectNameException, 
ReflectionException, InstanceNotFoundException {
+
+        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        ObjectName name = 
ObjectName.getInstance("java.lang:type=OperatingSystem");
+        AttributeList list = mbs.getAttributes(name, new String[] { 
"ProcessCpuLoad" });
+
+        if (list.isEmpty()) {
+            return Double.NaN;
+        }
+
+        Attribute att = (Attribute) list.get(0);
+        Double value = (Double) att.getValue();
+
+        if (value == -1.0) {
+            return Double.NaN;
+        }
+
+        return value * 100;
+    }
+
+}

Propchange: 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/CpuCheck.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/DiskSpaceCheck.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/DiskSpaceCheck.java?rev=1850371&view=auto
==============================================================================
--- 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/DiskSpaceCheck.java
 (added)
+++ 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/DiskSpaceCheck.java
 Fri Jan  4 14:48:42 2019
@@ -0,0 +1,123 @@
+/*
+ * 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 SF 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 org.apache.felix.hc.generalchecks;
+
+import static org.apache.felix.hc.generalchecks.util.UnitsUtil.formatBytes;
+
+import java.io.File;
+import java.util.Arrays;
+
+import org.apache.felix.hc.annotation.HealthCheckService;
+import org.apache.felix.hc.api.HealthCheck;
+import org.apache.felix.hc.api.Result;
+import org.apache.felix.hc.api.ResultLog;
+import org.apache.felix.hc.util.FormattingResultLog;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@HealthCheckService(name = DiskSpaceCheck.HC_NAME)
+@Component(configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = DiskSpaceCheck.Config.class, factory = true)
+public class DiskSpaceCheck implements HealthCheck {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(DiskSpaceCheck.class);
+
+    public static final String HC_NAME = "Disk Space";
+    public static final String HC_LABEL = "Health Check: " + HC_NAME;
+
+    @ObjectClassDefinition(name = HC_LABEL, description = "Checks the 
configured path(s) against the given thresholds")
+    public @interface Config {
+        @AttributeDefinition(name = "Name", description = "Name of this health 
check")
+        String hc_name() default HC_NAME;
+
+        @AttributeDefinition(name = "Tags", description = "List of tags for 
this health check, used to select subsets of health checks for execution e.g. 
by a composite health check.")
+        String[] hc_tags() default {};
+
+        @AttributeDefinition(name = "Disk used threshold for WARN", 
description = "in percent, if disk usage is over this limit the result is WARN")
+        long diskUsedThresholdWarn() default 90;
+
+        @AttributeDefinition(name = "Disk used threshold for CRITICAL", 
description = "in percent, if disk usage is over this limit the result is 
CRITICAL")
+        long diskUsedThresholdCritical() default 97;
+
+        @AttributeDefinition(name = "Paths to check for disk usage", 
description = "Paths that is checked for free space according the configured 
thresholds")
+        String[] diskPaths() default { "." };
+
+        @AttributeDefinition
+        String webconsole_configurationFactory_nameHint() default "{hc.name}: 
{diskPaths} used>{diskUsedThresholdWarn}% -> WARN  
used>{diskUsedThresholdCritical}% -> CRITICAL";
+    }
+
+    private long diskUsedThresholdWarn;
+    private long diskUsedThresholdCritical;
+    private String[] diskPaths;
+
+    @Activate
+    protected void activate(final Config config) {
+        diskUsedThresholdWarn = config.diskUsedThresholdWarn();
+        diskUsedThresholdCritical = config.diskUsedThresholdCritical();
+        diskPaths = config.diskPaths();
+
+        LOG.info("Activated disk usage HC for path(s) {} 
diskUsedThresholdWarn={}% diskUsedThresholdCritical={}%", 
Arrays.asList(diskPaths),
+                diskUsedThresholdWarn, diskUsedThresholdCritical);
+    }
+
+    @Override
+    public Result execute() {
+
+        FormattingResultLog log = new FormattingResultLog();
+
+        for (String diskPath : diskPaths) {
+
+            File diskPathFile = new File(diskPath);
+
+            if (!diskPathFile.exists()) {
+                log.warn("Directory '{}' does not exist", diskPathFile);
+                continue;
+            } else if (!diskPathFile.isDirectory()) {
+                log.warn("Directory '{}' is not a directory", diskPathFile);
+                continue;
+            }
+
+            double total = diskPathFile.getTotalSpace();
+            double free = diskPathFile.getUsableSpace();
+            double usedPercentage = (total - free) / total * 100d;
+
+            String totalStr = formatBytes(total);
+            String freeStr = formatBytes(free);
+            String msg = String.format("Disk Usage %s: %.1f%% of %s used / %s 
free", diskPathFile.getAbsolutePath(),
+                    usedPercentage,
+                    totalStr, freeStr);
+
+            Result.Status status = usedPercentage > 
this.diskUsedThresholdCritical ? Result.Status.CRITICAL
+                    : usedPercentage > this.diskUsedThresholdWarn ? 
Result.Status.WARN
+                            : Result.Status.OK;
+
+            log.add(new ResultLog.Entry(status, msg));
+
+        }
+
+        return new Result(log);
+    }
+
+
+}

Propchange: 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/DiskSpaceCheck.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/MemoryCheck.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/MemoryCheck.java?rev=1850371&view=auto
==============================================================================
--- 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/MemoryCheck.java
 (added)
+++ 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/MemoryCheck.java
 Fri Jan  4 14:48:42 2019
@@ -0,0 +1,99 @@
+/*
+ * 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 SF 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 org.apache.felix.hc.generalchecks;
+
+import static org.apache.felix.hc.generalchecks.util.UnitsUtil.formatBytes;
+
+import org.apache.felix.hc.annotation.HealthCheckService;
+import org.apache.felix.hc.api.HealthCheck;
+import org.apache.felix.hc.api.Result;
+import org.apache.felix.hc.api.ResultLog.Entry;
+import org.apache.felix.hc.util.FormattingResultLog;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@HealthCheckService(name = MemoryCheck.HC_NAME)
+@Component(configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = MemoryCheck.Config.class, factory = false)
+public class MemoryCheck implements HealthCheck {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(MemoryCheck.class);
+
+    public static final String HC_NAME = "Memory";
+    public static final String HC_LABEL = "Health Check: " + HC_NAME;
+
+    @ObjectClassDefinition(name = HC_LABEL, description = "Checks for high CPU 
load")
+    public @interface Config {
+        @AttributeDefinition(name = "Name", description = "Name of this health 
check")
+        String hc_name() default HC_NAME;
+
+        @AttributeDefinition(name = "Tags", description = "List of tags for 
this health check, used to select subsets of health checks for execution e.g. 
by a composite health check.")
+        String[] hc_tags() default {};
+
+        @AttributeDefinition(name = "Heap used threshold for WARN", 
description = "in percent, if heap usage is over this limit the result is WARN")
+        long heapUsedPercentageThresholdWarn() default 90;
+
+        @AttributeDefinition(name = "Heap used threshold for CRITICAL", 
description = "in percent, if heap usage is over this limit the result is 
CRITICAL")
+        long heapUsedPercentageThresholdCritical() default 99;
+    }
+
+    private long heapUsedPercentageThresholdWarn;
+    private long heapUsedPercentageThresholdCritical;
+
+    @Activate
+    protected void activate(final Config config) {
+        heapUsedPercentageThresholdWarn = 
config.heapUsedPercentageThresholdWarn();
+        heapUsedPercentageThresholdCritical = 
config.heapUsedPercentageThresholdCritical();
+        LOG.info("Activated Memory HC: heapUsedPercentageThresholdWarn={}% 
heapUsedPercentageThresholdCritical={}%", heapUsedPercentageThresholdWarn, 
heapUsedPercentageThresholdCritical);
+    }
+
+    @Override
+    public Result execute() {
+        FormattingResultLog log = new FormattingResultLog();
+
+        Runtime runtime = Runtime.getRuntime();
+
+        long freeMemory = runtime.freeMemory();
+        log.debug("Free memory: {}", formatBytes(freeMemory));
+        long currentlyAllocatedByJVM = runtime.totalMemory();
+        log.debug("Currently allocated memory: {}", 
formatBytes(currentlyAllocatedByJVM));
+        long usedMemory = currentlyAllocatedByJVM - freeMemory;
+        log.debug("Used memory: {}", formatBytes(usedMemory));
+        long maxMemoryAvailableToJVM = runtime.maxMemory();
+        
+        double memoryUsedPercentage = ((double) usedMemory / 
maxMemoryAvailableToJVM * 100d);
+
+        Result.Status status =
+                memoryUsedPercentage < this.heapUsedPercentageThresholdWarn ? 
Result.Status.OK :
+                        memoryUsedPercentage < 
this.heapUsedPercentageThresholdCritical ? Result.Status.WARN
+                                : Result.Status.CRITICAL;
+
+        String message = String.format("Memory Usage: %.1f%% of %s maximal 
heap used", memoryUsedPercentage, formatBytes(maxMemoryAvailableToJVM));
+
+        log.add(new Entry(status, message));
+
+        return new Result(log);
+    }
+
+}

Propchange: 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/MemoryCheck.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/ThreadUsageCheck.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/ThreadUsageCheck.java?rev=1850371&view=auto
==============================================================================
--- 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/ThreadUsageCheck.java
 (added)
+++ 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/ThreadUsageCheck.java
 Fri Jan  4 14:48:42 2019
@@ -0,0 +1,198 @@
+/*
+ * 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 SF 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 org.apache.felix.hc.generalchecks;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.hc.annotation.HealthCheckService;
+import org.apache.felix.hc.api.HealthCheck;
+import org.apache.felix.hc.api.Result;
+import org.apache.felix.hc.api.ResultLog;
+import org.apache.felix.hc.util.FormattingResultLog;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@HealthCheckService(name = ThreadUsageCheck.HC_NAME)
+@Component(configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = ThreadUsageCheck.Config.class, factory = false)
+public class ThreadUsageCheck implements HealthCheck {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(ThreadUsageCheck.class);
+
+    public static final String HC_NAME = "Thread Usage";
+    public static final String HC_LABEL = "Health Check: " + HC_NAME;
+
+    @ObjectClassDefinition(name = HC_LABEL, description = "Checks for thread 
usage and deadlocks")
+    public @interface Config {
+        @AttributeDefinition(name = "Name", description = "Name of this health 
check")
+        String hc_name() default HC_NAME;
+
+        @AttributeDefinition(name = "Tags", description = "List of tags for 
this health check, used to select subsets of health checks for execution e.g. 
by a composite health check.")
+        String[] hc_tags() default {};
+
+        @AttributeDefinition(name = "Sample Period", description = "Period to 
measure usage per thread")
+        long samplePeriodInMs() default 200;
+
+        @AttributeDefinition(name = "CPU Time Threshold for WARN in %", 
description = "Will WARN once this threshold is reached in average for all 
threads. This value is multiplied by number of available cores as reported by 
Runtime.getRuntime().availableProcessors()")
+        long cpuPercentageThresholdWarn() default 95;
+
+    }
+
+    private long samplePeriodInMs;
+
+    private long cpuPercentageThresholdWarn;
+
+    @Activate
+    protected final void activate(Config config) {
+        this.samplePeriodInMs = config.samplePeriodInMs();
+        this.cpuPercentageThresholdWarn = config.cpuPercentageThresholdWarn();
+        LOG.info("Activated thread usage HC samplePeriodInMs={}ms 
cpuPercentageThresholdWarn={}%", samplePeriodInMs, cpuPercentageThresholdWarn);
+    }
+
+    @Override
+    public Result execute() {
+        FormattingResultLog log = new FormattingResultLog();
+
+        log.debug("Checking threads for exceeding {}% CPU time within time 
period of {}ms", cpuPercentageThresholdWarn, samplePeriodInMs);
+
+        try {
+            ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
+
+            List<ThreadTimeInfo> threadTimeInfos = collectThreadTimeInfos(log, 
threadMxBean);
+
+            Collections.sort(threadTimeInfos);
+
+            float totalCpuTimePercentage = 0;
+            for (int i = 0; i < threadTimeInfos.size(); i++) {
+
+                ThreadTimeInfo threadInfo = threadTimeInfos.get(i);
+                float cpuTimePercentage = ((float) threadInfo.getCpuTime() / 
((float) samplePeriodInMs * 1000000)) * 100f;
+                totalCpuTimePercentage += cpuTimePercentage;
+
+                String msg = String.format("%4.1f", cpuTimePercentage) + "% 
used by thread \"" + threadInfo.name + "\"";
+                
+                // usually just shows the 3 busiest threads. For the case more 
threads take more than 15% CPU time, up to 10 threads are shown.
+                // use hcDebug=true to show all threads
+                if (i < 3 || (i < 10 && cpuTimePercentage > 15)) {
+                    log.info(msg);
+                } else {
+                    log.debug(msg);
+                }
+            }
+
+            int availableProcessors = 
Runtime.getRuntime().availableProcessors();
+            boolean isHighCpuTime = totalCpuTimePercentage > 
(cpuPercentageThresholdWarn * availableProcessors);
+            Result.Status status = isHighCpuTime ? Result.Status.WARN : 
Result.Status.OK;
+
+            double cpuTimePerProcessor = totalCpuTimePercentage / 
availableProcessors;
+            String msg = threadTimeInfos.size() + " threads using " + 
String.format("%.1f", totalCpuTimePercentage) + "% CPU Time ("
+                    + String.format("%.1f", cpuTimePerProcessor) + "% per 
single core having " + availableProcessors + " cores)";
+            if (isHighCpuTime) {
+                msg += ">" + cpuPercentageThresholdWarn + "% threshold for 
WARN";
+            }
+            log.add(new ResultLog.Entry(status, msg));
+
+            checkForDeadlock(log, threadMxBean);
+
+        } catch (Exception e) {
+            LOG.error("Could not analyse thread usage " + e, e);
+            log.healthCheckError("Could not analyse thread usage", e);
+        }
+
+        return new Result(log);
+
+    }
+
+    List<ThreadTimeInfo> collectThreadTimeInfos(FormattingResultLog log, 
ThreadMXBean threadMxBean) {
+
+        Map<Long, ThreadTimeInfo> threadTimeInfos = new HashMap<Long, 
ThreadTimeInfo>();
+
+        long[] allThreadIds = threadMxBean.getAllThreadIds();
+        for (long threadId : allThreadIds) {
+            ThreadTimeInfo threadTimeInfo = new ThreadTimeInfo();
+            long threadCpuTimeStart = threadMxBean.getThreadCpuTime(threadId);
+            threadTimeInfo.start = threadCpuTimeStart;
+            ThreadInfo threadInfo = threadMxBean.getThreadInfo(threadId);
+            threadTimeInfo.name = threadInfo != null ? 
threadInfo.getThreadName() : "Thread id " + threadId + " (name not resolvable)";
+            threadTimeInfos.put(threadId, threadTimeInfo);
+        }
+
+        try {
+            Thread.sleep(samplePeriodInMs);
+        } catch (InterruptedException e) {
+            log.warn("Could not sleep configured samplePeriodInMs={} to gather 
thread load", samplePeriodInMs);
+        }
+
+        for (long threadId : allThreadIds) {
+            ThreadTimeInfo threadTimeInfo = threadTimeInfos.get(threadId);
+            if (threadTimeInfo == null) {
+                continue;
+            }
+            long threadCpuTimeStop = threadMxBean.getThreadCpuTime(threadId);
+            threadTimeInfo.stop = threadCpuTimeStop;
+        }
+
+        List<ThreadTimeInfo> threads = new 
ArrayList<ThreadTimeInfo>(threadTimeInfos.values());
+
+        return threads;
+    }
+
+    void checkForDeadlock(FormattingResultLog log, ThreadMXBean threadMxBean) {
+        long[] findDeadlockedThreads = threadMxBean.findDeadlockedThreads();
+        if (findDeadlockedThreads != null) {
+            for (long threadId : findDeadlockedThreads) {
+                log.critical("Thread " + 
threadMxBean.getThreadInfo(threadId).getThreadName() + " is DEADLOCKED");
+            }
+        }
+    }
+
+    static class ThreadTimeInfo implements Comparable<ThreadTimeInfo> {
+        long start;
+        long stop;
+        String name;
+
+        long getCpuTime() {
+            long cpuTime = stop - start;
+            if (cpuTime < 0) {
+                cpuTime = 0;
+            }
+            return cpuTime;
+        }
+
+        @Override
+        public int compareTo(ThreadTimeInfo otherThreadTimeInfo) {
+            if (otherThreadTimeInfo == null) {
+                return -1;
+            }
+            return (int) (otherThreadTimeInfo.getCpuTime() - 
this.getCpuTime());
+        }
+    }
+}

Propchange: 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/ThreadUsageCheck.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/UnitsUtil.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/UnitsUtil.java?rev=1850371&view=auto
==============================================================================
--- 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/UnitsUtil.java
 (added)
+++ 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/UnitsUtil.java
 Fri Jan  4 14:48:42 2019
@@ -0,0 +1,41 @@
+/*
+ * 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 SF 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 org.apache.felix.hc.generalchecks.util;
+
+public class UnitsUtil {
+
+    private static final String SIZES[] = { "kB", "MB", "GB", "TB" };
+
+    public static String formatBytes(double size) {
+        double step = 1024, current = step;
+
+        int i;
+        for (i = 0; i < SIZES.length - 1; ++i) {
+            if (size < current * step) {
+                break;
+            }
+            current *= step;
+        }
+
+        String unit = SIZES[i];
+        double value = size / current;
+        String retVal = String.format("%.1f", value) + unit;
+        return retVal;
+    }
+    
+}

Propchange: 
felix/trunk/healthcheck/generalchecks/src/main/java/org/apache/felix/hc/generalchecks/util/UnitsUtil.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/UnitsUtilTest.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/UnitsUtilTest.java?rev=1850371&view=auto
==============================================================================
--- 
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/UnitsUtilTest.java
 (added)
+++ 
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/UnitsUtilTest.java
 Fri Jan  4 14:48:42 2019
@@ -0,0 +1,33 @@
+/*
+ * 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 SF 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 org.apache.felix.hc.generalchecks.util;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class UnitsUtilTest {
+
+    @Test
+    public void testFormatBytes() {
+        assertEquals("5.0MB", UnitsUtil.formatBytes(5d*1024*1024));
+        assertEquals("2.0GB", UnitsUtil.formatBytes(2d*1024*1024*1024));
+        assertEquals("706.1kB", UnitsUtil.formatBytes(722998));
+    }
+
+}

Propchange: 
felix/trunk/healthcheck/generalchecks/src/test/java/org/apache/felix/hc/generalchecks/util/UnitsUtilTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain


Reply via email to