This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-hc-support.git

commit 1cffc3b369990f2c6ea9226f78b550d55b620be7
Author: Bertrand Delacretaz <[email protected]>
AuthorDate: Thu Sep 26 13:17:13 2013 +0000

    SLING-3127 - prepare Health Check tools release
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1526476 
13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            | 115 ++++++++
 .../hc/support/impl/DefaultLoginsHealthCheck.java  | 119 ++++++++
 .../sling/hc/support/impl/InternalRequest.java     | 319 +++++++++++++++++++++
 .../sling/hc/support/impl/InternalResponse.java    | 185 ++++++++++++
 .../impl/SlingRequestStatusHealthCheck.java        | 139 +++++++++
 .../OSGI-INF/metatype/metatype.properties          |  52 ++++
 src/test/java/org/apache/sling/hc/healthcheck      |  44 +++
 .../healthchecks/DefaultLoginsHealthCheckTest.java |  70 +++++
 .../org/apache/sling/hc/healthchecks/SetField.java |  30 ++
 .../SlingRequestStatusHealthCheckTest.java         |  96 +++++++
 10 files changed, 1169 insertions(+)

diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..ce31b77
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>17</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.apache.sling</groupId>
+    <artifactId>org.apache.sling.hc.support</artifactId>
+    <packaging>bundle</packaging>
+    <version>0.0.2-SNAPSHOT</version>
+
+    <name>Sling Health Check Support Components</name>
+    <inceptionYear>2013</inceptionYear>
+    
+    <description>
+        Default Sling Health Check Support Components
+    </description>
+
+    <properties>
+        <sling.java.version>6</sling.java.version>
+    </properties>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.hc.core</artifactId>
+            <version>0.0.2-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.osgi</artifactId>
+            <version>2.2.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.api</artifactId>
+            <version>2.1.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.jcr.api</artifactId>
+            <version>2.0.4</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.engine</artifactId>
+            <version>2.2.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.6.2</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.jcr</groupId>
+            <artifactId>jcr</artifactId>
+        </dependency>
+         <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <version>1.6.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>1.9.5</version>
+            <scope>test</scope>
+        </dependency>
+     </dependencies>
+</project>
diff --git 
a/src/main/java/org/apache/sling/hc/support/impl/DefaultLoginsHealthCheck.java 
b/src/main/java/org/apache/sling/hc/support/impl/DefaultLoginsHealthCheck.java
new file mode 100644
index 0000000..adb2b23
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/hc/support/impl/DefaultLoginsHealthCheck.java
@@ -0,0 +1,119 @@
+/*
+ * 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.sling.hc.support.impl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.hc.api.HealthCheck;
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.util.FormattingResultLog;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** {@link HealthCheck} that checks that Sling default logins fail.
+ *  Used to verify that those logins are disabled on production systems */
+@Component(
+        name="org.apache.sling.hc.support.DefaultLoginsHealthCheck",
+        configurationFactory=true,
+        policy=ConfigurationPolicy.REQUIRE,
+        metatype=true)
+@Properties({
+    @Property(name=HealthCheck.NAME),
+    @Property(name=HealthCheck.TAGS, unbounded=PropertyUnbounded.ARRAY),
+    @Property(name=HealthCheck.MBEAN_NAME)
+})
+@Service(value=HealthCheck.class)
+public class DefaultLoginsHealthCheck implements HealthCheck {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Property(unbounded=PropertyUnbounded.ARRAY)
+    private static final String PROP_LOGINS = "logins";
+
+    private List<String> logins;
+
+    @Reference
+    private SlingRepository repository;
+
+    @Activate
+    public void activate(ComponentContext ctx) {
+        logins = 
Arrays.asList(PropertiesUtil.toStringArray(ctx.getProperties().get(PROP_LOGINS),
 new String[] {}));
+        log.info("Activated, logins={}", logins);
+    }
+
+    @Override
+    public Result execute() {
+        final FormattingResultLog resultLog = new FormattingResultLog();
+        int checked=0;
+        int failures=0;
+
+        for(String login : logins) {
+            final String [] parts = login.split(":");
+            if(parts.length != 2) {
+                resultLog.warn("Expected login in the form username:password, 
got [{}]", login);
+                continue;
+            }
+            checked++;
+            final String username = parts[0].trim();
+            final String password = parts[1].trim();
+            final Credentials creds = new SimpleCredentials(username, 
password.toCharArray());
+            Session s = null;
+            try {
+                s = repository.login(creds);
+                if(s != null) {
+                    failures++;
+                    resultLog.warn("Login as [{}] succeeded, was expecting it 
to fail", username);
+                } else {
+                    resultLog.debug("Login as [{}] didn't throw an Exception 
but returned null Session", username);
+                }
+            } catch(RepositoryException re) {
+                resultLog.debug("Login as [{}] failed, as expected", username);
+            } finally {
+                if(s != null) {
+                    s.logout();
+                }
+            }
+        }
+
+        if(checked==0) {
+            resultLog.warn("Did not check any logins, configured logins={}", 
logins);
+        } else if(failures != 0){
+            resultLog.warn("Checked {} logins, {} failures", checked, 
failures);
+        } else {
+            resultLog.debug("Checked {} logins, all successful", checked, 
failures);
+        }
+        return new Result(resultLog);
+    }
+}
\ No newline at end of file
diff --git 
a/src/main/java/org/apache/sling/hc/support/impl/InternalRequest.java 
b/src/main/java/org/apache/sling/hc/support/impl/InternalRequest.java
new file mode 100644
index 0000000..b79fdfe
--- /dev/null
+++ b/src/main/java/org/apache/sling/hc/support/impl/InternalRequest.java
@@ -0,0 +1,319 @@
+/*
+ * 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.sling.hc.support.impl;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+public class InternalRequest implements HttpServletRequest {
+
+    private final String path;
+    private final Map<String, Object> attributes = new HashMap<String, 
Object>();
+    
+    public InternalRequest(String path) {
+        this.path = path;
+    }
+    
+    @Override
+    public Object getAttribute(String key) {
+        return attributes.get(key);
+    }
+
+    @Override
+    public Enumeration<?> getAttributeNames() {
+        return new Vector<String>(attributes.keySet()).elements();
+    }
+
+    @Override
+    public String getCharacterEncoding() {
+        return "UTF-8";
+    }
+
+    @Override
+    public int getContentLength() {
+        return 0;
+    }
+
+    @Override
+    public String getContentType() {
+        return "text/plain";
+    }
+
+    @Override
+    public ServletInputStream getInputStream() throws IOException {
+        return new ServletInputStream() {
+            @Override
+            public int read() throws IOException {
+                return 0;
+            }
+        };
+    }
+
+    @Override
+    public String getLocalAddr() {
+        return "127.0.0.1";
+    }
+
+    @Override
+    public String getLocalName() {
+        return "localhost";
+    }
+
+    @Override
+    public int getLocalPort() {
+        return 0;
+    }
+
+    @Override
+    public Locale getLocale() {
+        return Locale.getDefault();
+    }
+
+    @Override
+    public Enumeration<?> getLocales() {
+        return new Vector<Locale>().elements();
+    }
+
+    @Override
+    public String getParameter(String arg0) {
+        return null;
+    }
+
+    @Override
+    public Map<?,?> getParameterMap() {
+        return new HashMap<String, Object>();
+    }
+
+    @Override
+    public Enumeration<?> getParameterNames() {
+        return new Vector<String>().elements();
+    }
+
+    @Override
+    public String[] getParameterValues(String arg0) {
+        return null;
+    }
+
+    @Override
+    public String getProtocol() {
+        return "http";
+    }
+
+    @Override
+    public BufferedReader getReader() throws IOException {
+        return new BufferedReader(new StringReader(""));
+    }
+
+    @Override
+    public String getRealPath(String arg0) {
+        return path;
+    }
+
+    @Override
+    public String getRemoteAddr() {
+        return "127.0.0.1";
+    }
+
+    @Override
+    public String getRemoteHost() {
+        return "localhost";
+    }
+
+    @Override
+    public int getRemotePort() {
+        return 1234;
+    }
+
+    @Override
+    public RequestDispatcher getRequestDispatcher(String arg0) {
+        return null;
+    }
+
+    @Override
+    public String getScheme() {
+        return "http";
+    }
+
+    @Override
+    public String getServerName() {
+        return "localhost";
+    }
+
+    @Override
+    public int getServerPort() {
+        return 80;
+    }
+
+    @Override
+    public boolean isSecure() {
+        return false;
+    }
+
+    @Override
+    public void removeAttribute(String arg0) {
+    }
+
+    @Override
+    public void setAttribute(String key, Object value) {
+        attributes.put(key, value);
+    }
+
+    @Override
+    public void setCharacterEncoding(String arg0)
+            throws UnsupportedEncodingException {
+    }
+
+    @Override
+    public String getAuthType() {
+        return null;
+    }
+
+    @Override
+    public String getContextPath() {
+        return "";
+    }
+
+    @Override
+    public Cookie[] getCookies() {
+        return null;
+    }
+
+    @Override
+    public long getDateHeader(String arg0) {
+        return 0;
+    }
+
+    @Override
+    public String getHeader(String arg0) {
+        return null;
+    }
+
+    @Override
+    public Enumeration<?> getHeaderNames() {
+        return new Vector<String>().elements();
+    }
+
+    @Override
+    public Enumeration<?> getHeaders(String arg0) {
+        return new Vector<String>().elements();
+    }
+
+    @Override
+    public int getIntHeader(String arg0) {
+        return 0;
+    }
+
+    @Override
+    public String getMethod() {
+        return "GET";
+    }
+
+    @Override
+    public String getPathInfo() {
+        return path;
+    }
+
+    @Override
+    public String getPathTranslated() {
+        return path;
+    }
+
+    @Override
+    public String getQueryString() {
+        return "";
+    }
+
+    @Override
+    public String getRemoteUser() {
+        return "remoteuser";
+    }
+
+    @Override
+    public String getRequestURI() {
+        return "http://localhost"; + path;
+    }
+
+    @Override
+    public StringBuffer getRequestURL() {
+        return new StringBuffer(getRequestURI());
+    }
+
+    @Override
+    public String getRequestedSessionId() {
+        return "";
+    }
+
+    @Override
+    public String getServletPath() {
+        return "";
+    }
+
+    @Override
+    public HttpSession getSession() {
+        return null;
+    }
+
+    @Override
+    public HttpSession getSession(boolean arg0) {
+        return null;
+    }
+
+    @Override
+    public Principal getUserPrincipal() {
+        return null;
+    }
+
+    @Override
+    public boolean isRequestedSessionIdFromCookie() {
+        return false;
+    }
+
+    @Override
+    public boolean isRequestedSessionIdFromURL() {
+        return false;
+    }
+
+    @Override
+    public boolean isRequestedSessionIdFromUrl() {
+        return false;
+    }
+
+    @Override
+    public boolean isRequestedSessionIdValid() {
+        return false;
+    }
+
+    @Override
+    public boolean isUserInRole(String arg0) {
+        return false;
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/hc/support/impl/InternalResponse.java 
b/src/main/java/org/apache/sling/hc/support/impl/InternalResponse.java
new file mode 100644
index 0000000..8752628
--- /dev/null
+++ b/src/main/java/org/apache/sling/hc/support/impl/InternalResponse.java
@@ -0,0 +1,185 @@
+/*
+ * 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.sling.hc.support.impl;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Locale;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+public class InternalResponse implements HttpServletResponse {
+
+    private int status = 200;
+    
+    private static class DevNullOutputStream extends ServletOutputStream {
+        @Override
+        public void write(int b) {
+        }
+    }
+    
+    @Override
+    public void flushBuffer() throws IOException {
+    }
+
+    @Override
+    public int getBufferSize() {
+        return 0;
+    }
+
+    @Override
+    public String getCharacterEncoding() {
+        return "UTF-8";
+    }
+
+    @Override
+    public String getContentType() {
+        return "text/plain";
+    }
+
+    @Override
+    public Locale getLocale() {
+        return Locale.getDefault();
+    }
+
+    @Override
+    public ServletOutputStream getOutputStream() throws IOException {
+        return new DevNullOutputStream();
+    }
+
+    @Override
+    public PrintWriter getWriter() throws IOException {
+        return new PrintWriter(new DevNullOutputStream());
+    }
+
+    @Override
+    public boolean isCommitted() {
+        return false;
+    }
+
+    @Override
+    public void reset() {
+    }
+
+    @Override
+    public void resetBuffer() {
+    }
+
+    @Override
+    public void setBufferSize(int arg0) {
+    }
+
+    @Override
+    public void setCharacterEncoding(String arg0) {
+    }
+
+    @Override
+    public void setContentLength(int arg0) {
+    }
+
+    @Override
+    public void setContentType(String arg0) {
+    }
+
+    @Override
+    public void setLocale(Locale arg0) {
+    }
+
+    @Override
+    public void addCookie(Cookie arg0) {
+    }
+
+    @Override
+    public void addDateHeader(String arg0, long arg1) {
+    }
+
+    @Override
+    public void addHeader(String arg0, String arg1) {
+    }
+
+    @Override
+    public void addIntHeader(String arg0, int arg1) {
+    }
+
+    @Override
+    public boolean containsHeader(String arg0) {
+        return false;
+    }
+
+    @Override
+    public String encodeRedirectURL(String url) {
+        return url;
+    }
+
+    @Override
+    public String encodeRedirectUrl(String url) {
+        return url;
+    }
+
+    @Override
+    public String encodeURL(String url) {
+        return url;
+    }
+
+    @Override
+    public String encodeUrl(String url) {
+        return url;
+    }
+
+    @Override
+    public void sendError(int s, String arg1) throws IOException {
+        status = s;
+    }
+
+    @Override
+    public void sendError(int s) throws IOException {
+        status = s;
+    }
+
+    @Override
+    public void sendRedirect(String arg0) throws IOException {
+    }
+
+    @Override
+    public void setDateHeader(String arg0, long arg1) {
+    }
+
+    @Override
+    public void setHeader(String arg0, String arg1) {
+    }
+
+    @Override
+    public void setIntHeader(String arg0, int arg1) {
+    }
+
+    @Override
+    public void setStatus(int s, String arg1) {
+        status = s;
+    }
+
+    @Override
+    public void setStatus(int s) {
+        status = s;
+    }
+    
+    public int getStatus() {
+        return status;
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/hc/support/impl/SlingRequestStatusHealthCheck.java
 
b/src/main/java/org/apache/sling/hc/support/impl/SlingRequestStatusHealthCheck.java
new file mode 100644
index 0000000..968174e
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/hc/support/impl/SlingRequestStatusHealthCheck.java
@@ -0,0 +1,139 @@
+/*
+ * 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.sling.hc.support.impl;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.engine.SlingRequestProcessor;
+import org.apache.sling.hc.api.HealthCheck;
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.util.FormattingResultLog;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** {@link HealthCheck} that checks the HTTP status of Sling requests.
+ *  Typically used to check that a freshly installed Sling-based system
+ *  is in good shape, contains all required content etc. */
+@Component(
+        name="org.apache.sling.hc.support.SlingRequestStatusHealthCheck",
+        configurationFactory=true,
+        policy=ConfigurationPolicy.REQUIRE,
+        metatype=true)
+@Properties({
+    @Property(name=HealthCheck.NAME),
+    @Property(name=HealthCheck.TAGS, unbounded=PropertyUnbounded.ARRAY),
+    @Property(name=HealthCheck.MBEAN_NAME)
+})
+@Service(value=HealthCheck.class)
+public class SlingRequestStatusHealthCheck implements HealthCheck {
+
+    private static final Logger log = 
LoggerFactory.getLogger(SlingRequestStatusHealthCheck.class);
+    private String [] paths;
+
+    static class PathSpec {
+        int status;
+        String path;
+
+        PathSpec(String configuredPath, FormattingResultLog resultLog) {
+            path = configuredPath;
+            status = 200;
+
+            final String [] parts  = configuredPath.split(":");
+            if(parts.length == 2) {
+                try {
+                    status = Integer.valueOf(parts[1].trim());
+                    path = parts[0].trim();
+                } catch(NumberFormatException nfe) {
+                    resultLog.healthCheckError("NumberFormatException while 
parsing [{}], invalid status value?", configuredPath);
+                }
+            }
+        }
+    }
+
+    @Property(unbounded=PropertyUnbounded.ARRAY)
+    private static final String PROP_PATH = "path";
+
+    @Reference
+    private SlingRequestProcessor requestProcessor;
+
+    @Reference
+    private ResourceResolverFactory resolverFactory;
+
+    @Activate
+    public void activate(final Map<String, Object> properties) {
+        paths = PropertiesUtil.toStringArray(properties.get(PROP_PATH), new 
String [] {});
+        log.info("Activated, paths={}", Arrays.asList(paths));
+    }
+
+    @Override
+    public Result execute() {
+        final FormattingResultLog resultLog = new FormattingResultLog();
+
+        ResourceResolver resolver = null;
+        int checked = 0;
+        int failed = 0;
+        String lastPath = null;
+
+        try {
+            resolver = resolverFactory.getAdministrativeResourceResolver(null);
+            for(String p : paths) {
+                lastPath = p;
+                final PathSpec ps = new PathSpec(p, resultLog);
+                final HttpServletRequest request = new 
InternalRequest(ps.path);
+                final InternalResponse response = new InternalResponse();
+                requestProcessor.processRequest(request, response, resolver);
+                final int status = response.getStatus();
+                if(status != ps.status) {
+                    failed++;
+                    resultLog.warn("[{}] returns status {}, expected {}", new 
Object[] { ps.path, status, ps.status });
+                } else {
+                    resultLog.debug("[{}] returns status {} as expected", 
ps.path, status);
+                }
+                checked++;
+            }
+        } catch(Exception e) {
+            resultLog.warn("Exception while executing request [{}]: {}", 
lastPath, e);
+        } finally {
+            if(resolver != null) {
+                resolver.close();
+            }
+        }
+
+        if(checked == 0) {
+            resultLog.warn("No paths checked, empty paths list?");
+        } else {
+            resultLog.debug("{} paths checked, {} failures", checked, failed);
+        }
+
+        return new Result(resultLog);
+    }
+}
\ No newline at end of file
diff --git a/src/main/resources/OSGI-INF/metatype/metatype.properties 
b/src/main/resources/OSGI-INF/metatype/metatype.properties
new file mode 100644
index 0000000..193b63b
--- /dev/null
+++ b/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,52 @@
+#
+#  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.
+#
+
+#
+# This file contains localization strings for configuration labels and
+# descriptions as used in the metatype.xml descriptor generated by the
+# the Sling SCR plugin
+
+org.apache.sling.hc.DefaultLoginsHealthCheck.name = Apache Sling  Default 
Logins Health Check 
+org.apache.sling.hc.DefaultLoginsHealthCheck.description = Expects default 
logins to fail, used to verify \
+    that they are disabled on production systems
+    
+org.apache.sling.hc.SlingRequestStatusHealthCheck.name = Apache Sling  Sling 
Request Status Health Check
+org.apache.sling.hc.SlingRequestStatusHealthCheck.description = Checks the 
HTTP status of Sling requests.
+
+hc.mbean.name.name = MBean name
+hc.mbean.name.description = Name of the MBean to create for this Health Check.
+
+hc.tags.name = Health Check tags
+hc.tags.description = List of tags for this Health Check service, used to 
select \
+    subsets of Health Check services for execution.
+
+hc.name.name = Health Check Name
+hc.name.description = Name of this Health Check service. Used for the MBean 
that's created \
+    for this Health Check as well, unless a specific MBean name is configured.
+
+logins.name = Login credentials
+logins.description = Which credentials to check. Each one is in the format 
"user:password" \
+    like "admin:admin" for example. Do *not* put any confidential passwords 
here, the goal \
+    is just to check that the default/demo logins, which passwords are known 
anyway, are \
+    disabled.
+
+path.name = Paths to check
+path.description = The list of paths to check, optionally with expected HTTP 
status responses. \
+    An entry like "/tmp/test.txt:301", for example, checks that /tmp/test.txt 
returns a \
+    301 response. 
diff --git a/src/test/java/org/apache/sling/hc/healthcheck 
b/src/test/java/org/apache/sling/hc/healthcheck
new file mode 100644
index 0000000..954f535
--- /dev/null
+++ b/src/test/java/org/apache/sling/hc/healthcheck
@@ -0,0 +1,44 @@
+package org.apache.sling.hc.impl.healthchecks;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class PathSpecTest {
+    private final String pathSpec;
+    private final String expectedPath;
+    private final int expectedStatus;
+    
+    @Parameters(name="{1}")
+    public static List<Object[]> data() {
+        final List<Object[]> result = new ArrayList<Object[]>();
+
+        result.add(new Object[] { "/one.html", "/one.html", 200 } ); 
+        result.add(new Object[] { "/two.html:404", "/two.html", 404 } ); 
+        result.add(new Object[] { "three.html : 404 ", "three.html", 404 } ); 
+        result.add(new Object[] { "four.html:not an integer", "four.html:not 
an integer", 200 } ); 
+        result.add(new Object[] { "", "", 200 } ); 
+
+        return result;
+    }
+
+    public PathSpecTest(String pathSpec, String expectedPath, int 
expectedStatus) {
+        this.pathSpec = pathSpec;
+        this.expectedPath = expectedPath;
+        this.expectedStatus = expectedStatus;
+    }
+    
+    @Test
+    public void testParsing() {
+        final SlingRequestStatusHealthCheck.PathSpec ps = new 
SlingRequestStatusHealthCheck.PathSpec(pathSpec);
+        assertEquals(expectedPath, ps.path);
+        assertEquals(expectedStatus, ps.status);
+    }
+}
diff --git 
a/src/test/java/org/apache/sling/hc/healthchecks/DefaultLoginsHealthCheckTest.java
 
b/src/test/java/org/apache/sling/hc/healthchecks/DefaultLoginsHealthCheckTest.java
new file mode 100644
index 0000000..862b6f8
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/hc/healthchecks/DefaultLoginsHealthCheckTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.sling.hc.healthchecks;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import javax.jcr.Credentials;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.support.impl.DefaultLoginsHealthCheck;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class DefaultLoginsHealthCheckTest {
+    
+    private Result getTestResult(String login) throws Exception {
+        final DefaultLoginsHealthCheck c = new DefaultLoginsHealthCheck();
+        SetField.set(c, "logins", Arrays.asList(new String[] { login }));
+        
+        final SlingRepository repo = Mockito.mock(SlingRepository.class);
+        SetField.set(c, "repository", repo);
+        final Session s = Mockito.mock(Session.class);
+        
Mockito.when(repo.login(Matchers.any(Credentials.class))).thenAnswer(new 
Answer<Session>() {
+            @Override
+            public Session answer(InvocationOnMock invocation) {
+                final SimpleCredentials c = 
(SimpleCredentials)invocation.getArguments()[0];
+                if("admin".equals(c.getUserID())) {
+                    return s;
+                }
+                return null;
+            }
+        });
+        
+        return c.execute();
+    }
+    
+    @Test
+    public void testHealthCheckFails() throws Exception {
+        assertFalse("Expecting failed check", 
getTestResult("admin:admin").isOk());
+    }
+    
+    @Test
+    public void testHealthCheckSucceeds() throws Exception {
+        assertTrue("Expecting successful check", 
getTestResult("FOO:bar").isOk());
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/hc/healthchecks/SetField.java 
b/src/test/java/org/apache/sling/hc/healthchecks/SetField.java
new file mode 100644
index 0000000..c4577a3
--- /dev/null
+++ b/src/test/java/org/apache/sling/hc/healthchecks/SetField.java
@@ -0,0 +1,30 @@
+/*
+ * 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.sling.hc.healthchecks;
+
+import java.lang.reflect.Field;
+
+public class SetField {
+    
+    public static void set(Object o, String name, Object value) throws 
Exception {
+        final Field f = o.getClass().getDeclaredField(name);
+        f.setAccessible(true);
+        f.set(o, value);
+    }
+    
+}
\ No newline at end of file
diff --git 
a/src/test/java/org/apache/sling/hc/healthchecks/SlingRequestStatusHealthCheckTest.java
 
b/src/test/java/org/apache/sling/hc/healthchecks/SlingRequestStatusHealthCheckTest.java
new file mode 100644
index 0000000..6731465
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/hc/healthchecks/SlingRequestStatusHealthCheckTest.java
@@ -0,0 +1,96 @@
+package org.apache.sling.hc.healthchecks;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.engine.SlingRequestProcessor;
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.support.impl.SlingRequestStatusHealthCheck;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+@RunWith(Parameterized.class)
+public class SlingRequestStatusHealthCheckTest {
+    private SlingRequestStatusHealthCheck hc;
+    private final Result.Status expectedStatus;
+    private final String [] paths;
+    
+    @Parameters(name="{0}")
+    public static List<Object[]> data() {
+            final List<Object[]> result = new ArrayList<Object[]>();
+            result.add(new Object[] { 
"200.html:200,502.html:1234,436.json:436", Result.Status.WARN });
+            
+            result.add(new Object[] { "", Result.Status.OK }); 
+            result.add(new Object[] { "200.x", Result.Status.OK }); 
+            result.add(new Object[] { "404.html:404", Result.Status.OK }); 
+            result.add(new Object[] { "200.html:200,502.html:502,436.json:436" 
, Result.Status.OK }); 
+            result.add(new Object[] { 
"200.html:1234,502.html:502,436.json:436" , Result.Status.WARN }); 
+            result.add(new Object[] { 
"200.html:200,502.html:1234,436.json:436" , Result.Status.WARN }); 
+            result.add(new Object[] { 
"200.html:200,502.html:502,436.json:1234" , Result.Status.WARN }); 
+            result.add(new Object[] { 
"200.html:1234,502.html:1234,436.json:1234" , Result.Status.WARN }); 
+            return result;
+    }
+    
+    @Before
+    public void setup() throws Exception {
+        hc = new SlingRequestStatusHealthCheck();
+        
+        final ResourceResolverFactory rrf = 
Mockito.mock(ResourceResolverFactory.class);
+        SetField.set(hc, "resolverFactory", rrf);
+        
+        final Answer<Void> a = new Answer<Void> () {
+            @Override
+            public Void answer(InvocationOnMock invocation) {
+                final HttpServletRequest request = 
(HttpServletRequest)invocation.getArguments()[0];
+                final HttpServletResponse response = 
(HttpServletResponse)invocation.getArguments()[1];
+                final String path = request.getPathInfo();
+                if(path.length() > 0) {
+                    final String status = path.substring(0, path.indexOf('.'));
+                    response.setStatus(Integer.valueOf(status));
+                }
+                return null;
+            }
+            
+        };
+        
+        final SlingRequestProcessor srp = 
Mockito.mock(SlingRequestProcessor.class);
+        SetField.set(hc, "requestProcessor", srp);
+        Mockito.doAnswer(a).when(srp).processRequest(
+                Matchers.any(HttpServletRequest.class),  
+                Matchers.any(HttpServletResponse.class), 
+                Matchers.any(ResourceResolver.class));
+        
+        
+        final Map<String, Object> properties = new HashMap<String, Object>();
+        properties.put("path", paths);
+        hc.activate(properties);
+    }
+    
+    public SlingRequestStatusHealthCheckTest(String paths, Result.Status 
expectedStatus) {
+        this.paths = paths.split(",");
+        this.expectedStatus = expectedStatus;
+        
+    }
+    
+    @Test
+    public void testResult() {
+        assertEquals("Expecting result " + expectedStatus + " for paths=" + 
paths,
+                expectedStatus, hc.execute().getStatus());
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
"[email protected]" <[email protected]>.

Reply via email to