You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 10:21:09 UTC

[sling-org-apache-sling-testing-sling-mock] annotated tag org.apache.sling.testing.sling-mock-1.1.0 created (now cd60db1)

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

rombert pushed a change to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git.


      at cd60db1  (tag)
 tagging 6687d06e53344138ae818d681c3767f53b46d17f (commit)
      by Stefan Seifert
      on Tue Dec 9 23:06:43 2014 +0000

- Log -----------------------------------------------------------------
org.apache.sling.testing.sling-mock-1.1.0
-----------------------------------------------------------------------

This annotated tag includes the following new commits:

     new 2aa4712  SLING-4042 Donate sling-mock, jcr-mock, osgi-mock implementation
     new d63d89c  svn:ignore
     new a6e7c1a  SLING-4042 move all mock projects to mocks/ subdirectory
     new d1f839a  SLING-4042 add missing package-info files
     new e9e968a  SLING-4042 per default no charencoding should be set in mock response
     new 43eb350  SLING-4042 do not forget to register ResourceResolverFactory in OSGi context as well
     new 3d36daf  SLING-4042 make sure JCR mock supports accessing data using multiple sessions
     new 4fc4baf  SLING-4042 add README files
     new 4aa90b9  add/update SCM urls
     new 22c8024  update to released versions
     new 1ba5459  [maven-release-plugin] prepare release org.apache.sling.testing.sling-mock-1.0.0
     new 5dcb3d7  [maven-release-plugin] prepare for next development iteration
     new 5b0b3fe  update dependencies in release process to next snapshot version
     new 1f52235  SLING-4085 NPE when using SlingContext rule without constructor argument
     new 9442dd8  SLING-4086 SlingHttpServlerRequest should support getResourceBundle() methods
     new 2f5faf4  set to released version now available on maven central
     new 6964d49  SLING-4090 Define package versions for Sling Mock, JCR Mock, OSGi Mock
     new 448fe45  SLING-4108 JCR/Sling/ResourceResolver Mock: Support providing authentication info
     new 5b4c01c  fix some javadoc errors and warnings
     new cb5f237  SLING-4162 Introduce "OsgiContext" junit rule for OSGi and OsgiContextImpl
     new e72ad4b  SLING-4229 add test cases for deep path access support in sling-mock as well
     new a07abf8  SLING-4108 default to getAdministrativeResourceResolver in sling-mock to support jackrabbit resource resolver adapter as well
     new 3cbedc6  fix some javadoc errors/warnings
     new 47cc45e  update to released versions
     new fccd947  [maven-release-plugin] prepare release org.apache.sling.testing.sling-mock-1.1.0
     new 6687d06  [maven-release-plugin]  copy for tag org.apache.sling.testing.sling-mock-1.1.0

The 26 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


-- 
To stop receiving notification emails like this one, please contact
['"commits@sling.apache.org" <co...@sling.apache.org>'].

[sling-org-apache-sling-testing-sling-mock] 11/26: [maven-release-plugin] prepare release org.apache.sling.testing.sling-mock-1.0.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 1ba54598e74cc6a9c29791c708f58ac5f25a8cea
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Oct 17 08:20:41 2014 +0000

    [maven-release-plugin] prepare release org.apache.sling.testing.sling-mock-1.0.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1632501 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index cf7943b..26139c1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
     </parent>
 
     <artifactId>org.apache.sling.testing.sling-mock</artifactId>
-    <version>1.0.0-SNAPSHOT</version>
+    <version>1.0.0</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling Testing Sling Mock</name>
@@ -39,9 +39,9 @@
     </properties>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/trunk/testing/mocks/sling-mock</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.sling-mock-1.0.0</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.sling-mock-1.0.0</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.testing.sling-mock-1.0.0</url>
     </scm>
 
     <dependencies>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 02/26: svn:ignore

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit d63d89cfc128ca2856c3789e145021481ef7f2f9
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Mon Oct 13 13:23:53 2014 +0000

    svn:ignore
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/sling-mock@1631387 13f79535-47bb-0310-9956-ffa450edef68

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 19/26: fix some javadoc errors and warnings

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 5b4c01c3ba1fee60feb73c641e53a8973bbf6013
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Thu Nov 6 00:32:42 2014 +0000

    fix some javadoc errors and warnings
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1637018 13f79535-47bb-0310-9956-ffa450edef68
---
 .../mock/sling/context/SlingContextImpl.java       | 10 ++-
 .../testing/mock/sling/junit/SlingContext.java     | 75 +++-------------------
 .../mock/sling/junit/SlingContextCallback.java     |  4 +-
 .../sling/servlet/MockSlingHttpServletRequest.java |  1 +
 4 files changed, 22 insertions(+), 68 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java b/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
index 65076aa..229b1e1 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
@@ -104,6 +104,7 @@ public class SlingContextImpl {
     
     /**
      * Initialize mocked resource resolver factory.
+     * @return Resource resolver factory
      */
     protected ResourceResolverFactory newResourceResolverFactory() {
         return ContextResourceResolverFactory.get(this.resourceResolverType);
@@ -277,6 +278,7 @@ public class SlingContextImpl {
 
     /**
      * Registers a service in the mocked OSGi environment.
+     * @param <T> Service type
      * @param service Service instance
      * @return Registered service instance
      */
@@ -286,6 +288,7 @@ public class SlingContextImpl {
 
     /**
      * Registers a service in the mocked OSGi environment.
+     * @param <T> Service type
      * @param serviceClass Service class
      * @param service Service instance
      * @return Registered service instance
@@ -296,6 +299,7 @@ public class SlingContextImpl {
 
     /**
      * Registers a service in the mocked OSGi environment.
+     * @param <T> Service type
      * @param serviceClass Service class
      * @param service Service instance
      * @param properties Service properties (optional)
@@ -314,6 +318,7 @@ public class SlingContextImpl {
     /**
      * Injects dependencies, activates and registers a service in the mocked
      * OSGi environment.
+     * @param <T> Service type
      * @param service Service instance
      * @return Registered service instance
      */
@@ -324,6 +329,7 @@ public class SlingContextImpl {
     /**
      * Injects dependencies, activates and registers a service in the mocked
      * OSGi environment.
+     * @param <T> Service type
      * @param service Service instance
      * @param properties Service properties (optional)
      * @return Registered service instance
@@ -337,6 +343,7 @@ public class SlingContextImpl {
 
     /**
      * Lookup a single service
+     * @param <ServiceType> Service type
      * @param serviceType The type (interface) of the service.
      * @return The service instance, or null if the service is not available.
      */
@@ -346,10 +353,11 @@ public class SlingContextImpl {
 
     /**
      * Lookup one or several services
+     * @param <ServiceType> Service type
      * @param serviceType The type (interface) of the service.
      * @param filter An optional filter (LDAP-like, see OSGi spec)
      * @return The services object or null.
-     * @throws InvalidServiceFilterSyntaxException If the <code>filter</code>
+     * @throws org.apache.sling.api.scripting.InvalidServiceFilterSyntaxException If the <code>filter</code>
      *             string is not a valid OSGi service filter string.
      */
     public final <ServiceType> ServiceType[] getServices(final Class<ServiceType> serviceType, final String filter) {
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContext.java b/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContext.java
index 51ea608..56413d3 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContext.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContext.java
@@ -37,34 +37,15 @@ public final class SlingContext extends SlingContextImpl implements TestRule {
     private final TestRule delegate;
 
     /**
-     * Initialize Sling context.
-     * <p>
-     * If context is initialized with:
-     * </p>
-     * <ul>
-     * <li>No resource resolver type - default is used
-     * {@link MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.</li>
-     * <li>One resource resolver type - exactly this is used.</li>
-     * <li>More than one: all unit test methods are executed for all resource
-     * resolver types using {@link ListGenerator}.</li>
-     * </ul>
+     * Initialize Sling context with default resource resolver type:
+     * {@link org.apache.sling.testing.mock.sling.MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.
      */
     public SlingContext() {
         this(null, null, null);
     }
 
     /**
-     * Initialize Sling context.
-     * <p>
-     * If context is initialized with:
-     * </p>
-     * <ul>
-     * <li>No resource resolver type - default is used
-     * {@link MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.</li>
-     * <li>One resource resolver type - exactly this is used.</li>
-     * <li>More than one: all unit test methods are executed for all resource
-     * resolver types using {@link ListGenerator}.</li>
-     * </ul>
+     * Initialize Sling context with resource resolver type.
      * @param resourceResolverType Resource resolver type.
      */
     public SlingContext(final ResourceResolverType resourceResolverType) {
@@ -72,17 +53,8 @@ public final class SlingContext extends SlingContextImpl implements TestRule {
     }
 
     /**
-     * Initialize Sling context.
-     * <p>
-     * If context is initialized with:
-     * </p>
-     * <ul>
-     * <li>No resource resolver type - default is used
-     * {@link MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.</li>
-     * <li>One resource resolver type - exactly this is used.</li>
-     * <li>More than one: all unit test methods are executed for all resource
-     * resolver types using {@link ListGenerator}.</li>
-     * </ul>
+     * Initialize Sling context with default resource resolver type:
+     * {@link org.apache.sling.testing.mock.sling.MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.
      * @param setUpCallback Allows the application to register an own callback
      *            function that is called after the built-in setup rules are
      *            executed.
@@ -92,17 +64,7 @@ public final class SlingContext extends SlingContextImpl implements TestRule {
     }
 
     /**
-     * Initialize Sling context.
-     * <p>
-     * If context is initialized with:
-     * </p>
-     * <ul>
-     * <li>No resource resolver type - default is used
-     * {@link MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.</li>
-     * <li>One resource resolver type - exactly this is used.</li>
-     * <li>More than one: all unit test methods are executed for all resource
-     * resolver types using {@link ListGenerator}.</li>
-     * </ul>
+     * Initialize Sling context with resource resolver type.
      * @param setUpCallback Allows the application to register an own callback
      *            function that is called after the built-in setup rules are
      *            executed.
@@ -113,17 +75,8 @@ public final class SlingContext extends SlingContextImpl implements TestRule {
     }
 
     /**
-     * Initialize Sling context.
-     * <p>
-     * If context is initialized with:
-     * </p>
-     * <ul>
-     * <li>No resource resolver type - default is used
-     * {@link MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.</li>
-     * <li>One resource resolver type - exactly this is used.</li>
-     * <li>More than one: all unit test methods are executed for all resource
-     * resolver types using {@link ListGenerator}.</li>
-     * </ul>
+     * Initialize Sling context with default resource resolver type:
+     * {@link org.apache.sling.testing.mock.sling.MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.
      * @param setUpCallback Allows the application to register an own callback
      *            function that is called after the built-in setup rules are
      *            executed.
@@ -136,17 +89,7 @@ public final class SlingContext extends SlingContextImpl implements TestRule {
     }
     
     /**
-     * Initialize Sling context.
-     * <p>
-     * If context is initialized with:
-     * </p>
-     * <ul>
-     * <li>No resource resolver type - default is used
-     * {@link MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.</li>
-     * <li>One resource resolver type - exactly this is used.</li>
-     * <li>More than one: all unit test methods are executed for all resource
-     * resolver types using {@link ListGenerator}.</li>
-     * </ul>
+     * Initialize Sling context with resource resolver type.
      * @param setUpCallback Allows the application to register an own callback
      *            function that is called after the built-in setup rules are
      *            executed.
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContextCallback.java b/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContextCallback.java
index 913b832..908301c 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContextCallback.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContextCallback.java
@@ -24,13 +24,15 @@ import org.apache.sling.api.resource.PersistenceException;
 
 /**
  * Callback-interface for application-specific setup and teardown operations to
- * customize the {@link AemContext} JUnit rule.
+ * customize the {@link SlingContext} JUnit rule.
  */
 public interface SlingContextCallback {
 
     /**
      * Execute callback action
      * @param context Sling context
+     * @throws IOException
+     * @throws PersistenceException
      */
     void execute(SlingContext context) throws IOException, PersistenceException;
 
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequest.java b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequest.java
index eaad0bf..b776bf4 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequest.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequest.java
@@ -110,6 +110,7 @@ public class MockSlingHttpServletRequest extends SlingAdaptable implements Sling
 
     /**
      * @param resourceResolver Resource resolver
+     * @param bundleContext Bundle context
      */
     public MockSlingHttpServletRequest(ResourceResolver resourceResolver, BundleContext bundleContext) {
         this.resourceResolver = resourceResolver;

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 09/26: add/update SCM urls

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 4aa90b9efc3bc7af64fbaae977255fd03524b7cd
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Oct 17 08:10:43 2014 +0000

    add/update SCM urls
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1632490 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/pom.xml b/pom.xml
index f314611..4fcb1cc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,6 +38,12 @@
         <sling.java.version>6</sling.java.version>
     </properties>
 
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/testing/mocks/sling-mock</url>
+    </scm>
+
     <dependencies>
   
         <dependency>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 04/26: SLING-4042 add missing package-info files

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit d1f839a3f4ed96c7737014f4acc18f60cf026912
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Mon Oct 13 15:27:41 2014 +0000

    SLING-4042 add missing package-info files
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1631438 13f79535-47bb-0310-9956-ffa450edef68
---
 .../testing/mock/sling/services/package-info.java  | 22 ++++++++++++++++++++++
 .../sling/testing/mock/sling/spi/package-info.java | 22 ++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/src/main/java/org/apache/sling/testing/mock/sling/services/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/services/package-info.java
new file mode 100644
index 0000000..6267725
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/services/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * Mocks for selected Sling services.
+ */
+package org.apache.sling.testing.mock.sling.services;
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/spi/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/spi/package-info.java
new file mode 100644
index 0000000..082a28a
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/spi/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * SPI for hooking in alternative resource type adapter implementations.
+ */
+package org.apache.sling.testing.mock.sling.spi;

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 18/26: SLING-4108 JCR/Sling/ResourceResolver Mock: Support providing authentication info

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 448fe45364baf956e8aedf5922e32766015707eb
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Oct 28 10:17:59 2014 +0000

    SLING-4108 JCR/Sling/ResourceResolver Mock: Support providing authentication info
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1634835 13f79535-47bb-0310-9956-ffa450edef68
---
 .../mock/sling/MockJcrResourceResolverFactory.java | 25 ++++++++++++++++------
 .../testing/mock/sling/MockSlingRepository.java    | 10 ++++-----
 .../AbstractMultipleResourceResolverTest.java      | 13 +++++++++--
 3 files changed, 34 insertions(+), 14 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/sling/MockJcrResourceResolverFactory.java b/src/main/java/org/apache/sling/testing/mock/sling/MockJcrResourceResolverFactory.java
index 8a9716b..f4fc1f1 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/MockJcrResourceResolverFactory.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/MockJcrResourceResolverFactory.java
@@ -53,8 +53,7 @@ class MockJcrResourceResolverFactory implements ResourceResolverFactory {
         this.slingRepository = repository;
     }
 
-    @Override
-    public ResourceResolver getResourceResolver(final Map<String, Object> authenticationInfo) throws LoginException {
+    private ResourceResolver getResourceResolverInternal(Map<String, Object> authenticationInfo, boolean isAdmin) throws LoginException {
         // setup mock OSGi environment
         Dictionary<String, Object> resourceProviderFactoryProps = new Hashtable<String, Object>();
         resourceProviderFactoryProps.put(Constants.SERVICE_VENDOR, "sling-mock");
@@ -72,8 +71,15 @@ class MockJcrResourceResolverFactory implements ResourceResolverFactory {
         MockOsgi.injectServices(jcrResourceProviderFactory, componentContext.getBundleContext());
         MockOsgi.activate(jcrResourceProviderFactory, componentContext.getBundleContext(),
                 ImmutableMap.<String, Object> of());
-        ResourceProvider resourceProvider = jcrResourceProviderFactory
-                .getAdministrativeResourceProvider(new HashMap<String, Object>());
+        
+        ResourceProvider resourceProvider;
+        if (isAdmin) {
+            resourceProvider = jcrResourceProviderFactory.getAdministrativeResourceProvider(authenticationInfo);
+        }
+        else {
+            resourceProvider = jcrResourceProviderFactory.getResourceProvider(authenticationInfo);
+        }
+        
         Dictionary<Object, Object> resourceProviderProps = new Hashtable<Object, Object>();
         resourceProviderProps.put(ResourceProvider.ROOTS, new String[] { "/" });
         componentContext.getBundleContext().registerService(ResourceProvider.class.getName(), resourceProvider,
@@ -88,7 +94,7 @@ class MockJcrResourceResolverFactory implements ResourceResolverFactory {
                 getServiceReferenceProperties(resourceProviderServiceReference));
         activator.activate(componentContext);
         CommonResourceResolverFactoryImpl commonFactoryImpl = new CommonResourceResolverFactoryImpl(activator);
-        ResourceResolverContext context = new ResourceResolverContext(true, null, new ResourceAccessSecurityTracker());
+        ResourceResolverContext context = new ResourceResolverContext(true, authenticationInfo, new ResourceAccessSecurityTracker());
         ResourceResolverImpl resourceResolver = new ResourceResolverImpl(commonFactoryImpl, context);
         return resourceResolver;
     }
@@ -103,15 +109,20 @@ class MockJcrResourceResolverFactory implements ResourceResolverFactory {
     }
 
     @Override
+    public ResourceResolver getResourceResolver(final Map<String, Object> authenticationInfo) throws LoginException {
+        return getResourceResolverInternal(authenticationInfo, false);
+    }
+    
+    @Override
     public ResourceResolver getAdministrativeResourceResolver(final Map<String, Object> authenticationInfo)
             throws LoginException {
-        return getResourceResolver(authenticationInfo);
+        return getResourceResolverInternal(authenticationInfo, true);
     }
 
     // part of Sling API 2.7
     public ResourceResolver getServiceResourceResolver(final Map<String, Object> authenticationInfo)
             throws LoginException {
-        return getResourceResolver(authenticationInfo);
+        return getResourceResolverInternal(authenticationInfo, true);
     }
 
 }
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/MockSlingRepository.java b/src/main/java/org/apache/sling/testing/mock/sling/MockSlingRepository.java
index 1e33847..eec41f5 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/MockSlingRepository.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/MockSlingRepository.java
@@ -41,14 +41,14 @@ class MockSlingRepository implements SlingRepository {
     }
 
     @Override
-    public Session loginAdministrative(final String workspace) throws RepositoryException {
-        return login();
+    public Session loginAdministrative(final String workspaceName) throws RepositoryException {
+        return login(workspaceName);
     }
 
     @Override
-    public Session loginService(final String subServiceName, final String workspace) throws LoginException,
-            RepositoryException {
-        return login();
+    public Session loginService(final String subServiceName, final String workspaceName)
+            throws LoginException, RepositoryException {
+        return login(workspaceName);
     }
 
     @Override
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractMultipleResourceResolverTest.java b/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractMultipleResourceResolverTest.java
index 1ce615e..ea47667 100644
--- a/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractMultipleResourceResolverTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractMultipleResourceResolverTest.java
@@ -44,8 +44,17 @@ public abstract class AbstractMultipleResourceResolverTest {
     @Test
     public void testMultipleResourceResolver() throws Exception {
         ResourceResolverFactory factory = newResourceResolerFactory();
-        ResourceResolver resolver1 = factory.getResourceResolver(null);
-        ResourceResolver resolver2 = factory.getResourceResolver(null);
+        ResourceResolver resolver1 = factory.getResourceResolver(ImmutableMap.<String, Object>of(
+                ResourceResolverFactory.USER, "user1"));
+        ResourceResolver resolver2 = factory.getResourceResolver(ImmutableMap.<String, Object>of(
+                ResourceResolverFactory.USER, "user2"));
+        
+        // validate user names
+        // TODO: enable this tests when updated to latest jcr-mock/resourceresolver-mock versions
+        /*
+        assertEquals("user1", resolver1.getAttribute(ResourceResolverFactory.USER));
+        assertEquals("user2", resolver2.getAttribute(ResourceResolverFactory.USER));
+        */
         
         // add a resource in resolver 1
         Resource root = resolver1.getResource("/");

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 14/26: SLING-4085 NPE when using SlingContext rule without constructor argument

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 1f522355aaed60502df5db0138cb22deb2659ada
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Oct 21 19:22:32 2014 +0000

    SLING-4085 NPE when using SlingContext rule without constructor argument
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1633438 13f79535-47bb-0310-9956-ffa450edef68
---
 .../context/ContextResourceResolverFactory.java    | 12 ++++---
 .../mock/sling/context/SlingContextImplTest.java   |  8 +++++
 .../sling/junit/SlingContextDefaultRRTypeTest.java | 37 ++++++++++++++++++++++
 3 files changed, 53 insertions(+), 4 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java b/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java
index 2891fc6..8df107f 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java
@@ -38,10 +38,14 @@ final class ContextResourceResolverFactory {
     }
 
     public static ResourceResolverFactory get(final ResourceResolverType resourceResolverType) {
+        ResourceResolverType type = resourceResolverType;
+        if (type == null) {
+            type = MockSling.DEFAULT_RESOURCERESOLVER_TYPE;
+        }
         try {
-            ResourceResolverFactory factory = MockSling.newResourceResolverFactory(resourceResolverType);
+            ResourceResolverFactory factory = MockSling.newResourceResolverFactory(type);
 
-            switch (resourceResolverType) {
+            switch (type) {
             case JCR_MOCK:
                 initializeJcrMock(factory);
                 break;
@@ -52,12 +56,12 @@ final class ContextResourceResolverFactory {
                 initializeResourceResolverMock(factory);
                 break;
             default:
-                throw new IllegalArgumentException("Invalid resource resolver type: " + resourceResolverType);
+                throw new IllegalArgumentException("Invalid resource resolver type: " + type);
             }
 
             return factory;
         } catch (Throwable ex) {
-            throw new RuntimeException("Unable to initialize " + resourceResolverType + " resource resolver factory.", ex);
+            throw new RuntimeException("Unable to initialize " + type + " resource resolver factory.", ex);
         }
     }
 
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java b/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java
index d667002..2c7aed5 100644
--- a/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java
@@ -200,6 +200,14 @@ public class SlingContextImplTest {
         assertNotNull(factory);
     }
 
+    @Test
+    public void testWithoutResourceResolverType() {
+        SlingContextImpl contextTest = new SlingContextImpl();
+        contextTest.setUp();
+        ResourceResolverFactory factory = contextTest.getService(ResourceResolverFactory.class);
+        assertNotNull(factory);
+    }
+
     @Model(adaptables = SlingHttpServletRequest.class)
     public interface RequestAttributeModel {
         @Inject
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/junit/SlingContextDefaultRRTypeTest.java b/src/test/java/org/apache/sling/testing/mock/sling/junit/SlingContextDefaultRRTypeTest.java
new file mode 100644
index 0000000..d5579af
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/junit/SlingContextDefaultRRTypeTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.junit;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+public class SlingContextDefaultRRTypeTest {
+
+    // Run all unit tests for each resource resolver types listed here
+    @Rule
+    public SlingContext context = new SlingContext();
+
+    @Test
+    public void testRequest() {
+        assertNotNull(context.request());
+    }
+
+}

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 23/26: fix some javadoc errors/warnings

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 3cbedc6960801a9df617a163f8206393bdf3e796
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Dec 9 23:01:37 2014 +0000

    fix some javadoc errors/warnings
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1644220 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/sling/testing/mock/sling/junit/SlingContextCallback.java   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContextCallback.java b/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContextCallback.java
index 908301c..247185b 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContextCallback.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContextCallback.java
@@ -31,8 +31,8 @@ public interface SlingContextCallback {
     /**
      * Execute callback action
      * @param context Sling context
-     * @throws IOException
-     * @throws PersistenceException
+     * @throws IOException I/O exception
+     * @throws PersistenceException Persistence exception
      */
     void execute(SlingContext context) throws IOException, PersistenceException;
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 20/26: SLING-4162 Introduce "OsgiContext" junit rule for OSGi and OsgiContextImpl

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit cb5f2377fd889cc8fbe3e3970ee7c4d75904bf0a
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Nov 14 09:55:05 2014 +0000

    SLING-4162 Introduce "OsgiContext" junit rule for OSGi and OsgiContextImpl
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1639589 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            |   2 +-
 .../mock/sling/context/SlingContextImpl.java       | 122 ++-------------------
 .../testing/mock/sling/context/package-info.java   |   2 +-
 .../testing/mock/sling/junit/SlingContext.java     |   6 +-
 .../testing/mock/sling/junit/package-info.java     |   2 +-
 .../mock/sling/context/SlingContextImplTest.java   |  44 --------
 .../testing/mock/sling/junit/SlingContextTest.java |  10 --
 7 files changed, 14 insertions(+), 174 deletions(-)

diff --git a/pom.xml b/pom.xml
index 66a28ce..c3621a9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,7 +49,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
-            <version>1.0.0</version>
+            <version>1.0.1-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
         <dependency>
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java b/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
index 229b1e1..976c4e0 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
@@ -18,9 +18,6 @@
  */
 package org.apache.sling.testing.mock.sling.context;
 
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.Map;
 import java.util.Set;
 
 import javax.jcr.RepositoryException;
@@ -47,7 +44,7 @@ import org.apache.sling.models.impl.injectors.ValueMapInjector;
 import org.apache.sling.models.spi.ImplementationPicker;
 import org.apache.sling.models.spi.Injector;
 import org.apache.sling.settings.SlingSettingsService;
-import org.apache.sling.testing.mock.osgi.MockOsgi;
+import org.apache.sling.testing.mock.osgi.context.OsgiContextImpl;
 import org.apache.sling.testing.mock.sling.MockSling;
 import org.apache.sling.testing.mock.sling.ResourceResolverType;
 import org.apache.sling.testing.mock.sling.builder.ContentBuilder;
@@ -58,11 +55,10 @@ import org.apache.sling.testing.mock.sling.services.MockSlingSettingService;
 import org.apache.sling.testing.mock.sling.servlet.MockRequestPathInfo;
 import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
 import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletResponse;
-import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
-import org.osgi.service.component.ComponentContext;
 
-import com.google.common.collect.ImmutableMap;
+import aQute.bnd.annotation.ConsumerType;
+
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -70,7 +66,8 @@ import com.google.common.collect.ImmutableSet;
  * directly but via the {@link org.apache.sling.testing.mock.sling.junit.SlingContext} JUnit
  * rule.
  */
-public class SlingContextImpl {
+@ConsumerType
+public class SlingContextImpl extends OsgiContextImpl {
 
     // default to publish instance run mode
     static final Set<String> DEFAULT_RUN_MODES = ImmutableSet.<String> builder().add("publish").build();
@@ -78,7 +75,6 @@ public class SlingContextImpl {
     protected ResourceResolverFactory resourceResolverFactory;
     protected MockModelAdapterFactory modelAdapterFactory;
     protected ResourceResolverType resourceResolverType;
-    protected ComponentContext componentContext;
     protected ResourceResolver resourceResolver;
     protected MockSlingHttpServletRequest request;
     protected MockSlingHttpServletResponse response;
@@ -97,6 +93,7 @@ public class SlingContextImpl {
      * Setup actions before test method execution
      */
     protected void setUp() {
+        super.setUp();
         MockSling.setAdapterManagerBundleContext(bundleContext());
         this.resourceResolverFactory = newResourceResolverFactory();
         registerDefaultServices();
@@ -171,6 +168,8 @@ public class SlingContextImpl {
         this.contentBuilder = null;
 
         MockSling.clearAdapterManagerBundleContext();
+        
+        super.tearDown();
     }
 
     /**
@@ -181,23 +180,6 @@ public class SlingContextImpl {
     }
 
     /**
-     * @return OSGi component context
-     */
-    public final ComponentContext componentContext() {
-        if (this.componentContext == null) {
-            this.componentContext = MockOsgi.newComponentContext();
-        }
-        return this.componentContext;
-    }
-
-    /**
-     * @return OSGi Bundle context
-     */
-    public final BundleContext bundleContext() {
-        return componentContext().getBundleContext();
-    }
-
-    /**
      * @return Resource resolver
      */
     public final ResourceResolver resourceResolver() {
@@ -277,94 +259,6 @@ public class SlingContextImpl {
     }
 
     /**
-     * Registers a service in the mocked OSGi environment.
-     * @param <T> Service type
-     * @param service Service instance
-     * @return Registered service instance
-     */
-    public final <T> T registerService(final T service) {
-        return registerService(null, service, null);
-    }
-
-    /**
-     * Registers a service in the mocked OSGi environment.
-     * @param <T> Service type
-     * @param serviceClass Service class
-     * @param service Service instance
-     * @return Registered service instance
-     */
-    public final <T> T registerService(final Class<T> serviceClass, final T service) {
-        return registerService(serviceClass, service, null);
-    }
-
-    /**
-     * Registers a service in the mocked OSGi environment.
-     * @param <T> Service type
-     * @param serviceClass Service class
-     * @param service Service instance
-     * @param properties Service properties (optional)
-     * @return Registered service instance
-     */
-    public final <T> T registerService(final Class<T> serviceClass, final T service, final Map<String, Object> properties) {
-        Dictionary<String, Object> serviceProperties = null;
-        if (properties != null) {
-            serviceProperties = new Hashtable<String, Object>(properties);
-        }
-        bundleContext().registerService(serviceClass != null ? serviceClass.getName() : null, service,
-                serviceProperties);
-        return service;
-    }
-
-    /**
-     * Injects dependencies, activates and registers a service in the mocked
-     * OSGi environment.
-     * @param <T> Service type
-     * @param service Service instance
-     * @return Registered service instance
-     */
-    public final <T> T registerInjectActivateService(final T service) {
-        return registerInjectActivateService(service, ImmutableMap.<String, Object> of());
-    }
-
-    /**
-     * Injects dependencies, activates and registers a service in the mocked
-     * OSGi environment.
-     * @param <T> Service type
-     * @param service Service instance
-     * @param properties Service properties (optional)
-     * @return Registered service instance
-     */
-    public final <T> T registerInjectActivateService(final T service, final Map<String, Object> properties) {
-        MockOsgi.injectServices(service, bundleContext());
-        MockOsgi.activate(service, bundleContext(), properties);
-        registerService(null, service, null);
-        return service;
-    }
-
-    /**
-     * Lookup a single service
-     * @param <ServiceType> Service type
-     * @param serviceType The type (interface) of the service.
-     * @return The service instance, or null if the service is not available.
-     */
-    public final <ServiceType> ServiceType getService(final Class<ServiceType> serviceType) {
-        return slingScriptHelper().getService(serviceType);
-    }
-
-    /**
-     * Lookup one or several services
-     * @param <ServiceType> Service type
-     * @param serviceType The type (interface) of the service.
-     * @param filter An optional filter (LDAP-like, see OSGi spec)
-     * @return The services object or null.
-     * @throws org.apache.sling.api.scripting.InvalidServiceFilterSyntaxException If the <code>filter</code>
-     *             string is not a valid OSGi service filter string.
-     */
-    public final <ServiceType> ServiceType[] getServices(final Class<ServiceType> serviceType, final String filter) {
-        return slingScriptHelper().getServices(serviceType, filter);
-    }
-
-    /**
      * @return Current resource
      */
     public final Resource currentResource() {
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/context/package-info.java
index ca62fc4..cd3a4a5 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/context/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/package-info.java
@@ -19,5 +19,5 @@
 /**
  * Sling context implementation for unit tests.
  */
-@aQute.bnd.annotation.Version("1.0")
+@aQute.bnd.annotation.Version("2.0")
 package org.apache.sling.testing.mock.sling.context;
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContext.java b/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContext.java
index 56413d3..5e0b48c 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContext.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContext.java
@@ -33,7 +33,6 @@ public final class SlingContext extends SlingContextImpl implements TestRule {
 
     private final SlingContextCallback setUpCallback;
     private final SlingContextCallback tearDownCallback;
-    private final ResourceResolverType resourceResolverType;
     private final TestRule delegate;
 
     /**
@@ -103,10 +102,11 @@ public final class SlingContext extends SlingContextImpl implements TestRule {
 
         this.setUpCallback = setUpCallback;
         this.tearDownCallback = tearDownCallback;
-        this.resourceResolverType = resourceResolverType;
 
-        // user default rule that directly executes each test method once
+        // set resource resolver type in parent context
         setResourceResolverType(this.resourceResolverType);
+
+        // wrap {@link ExternalResource} rule executes each test method once
         this.delegate = new ExternalResource() {
             @Override
             protected void before() {
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/junit/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/junit/package-info.java
index 4700e5a..09b2c65 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/junit/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/junit/package-info.java
@@ -19,5 +19,5 @@
 /**
  * Rule for providing easy access to Sling context in JUnit tests.
  */
-@aQute.bnd.annotation.Version("1.0")
+@aQute.bnd.annotation.Version("2.0")
 package org.apache.sling.testing.mock.sling.junit;
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java b/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java
index 2c7aed5..817c502 100644
--- a/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java
@@ -24,9 +24,6 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
 
 import javax.inject.Inject;
@@ -47,7 +44,6 @@ import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.osgi.framework.ServiceReference;
 
 public class SlingContextImplTest {
 
@@ -89,41 +85,6 @@ public class SlingContextImplTest {
     }
 
     @Test
-    public void testRegisterService() {
-        Set<String> myService = new HashSet<String>();
-        context.registerService(Set.class, myService);
-
-        Set<?> serviceResult = context.getService(Set.class);
-        assertSame(myService, serviceResult);
-    }
-
-    @Test
-    public void testRegisterServiceWithProperties() {
-        Map<String, Object> props = new HashMap<String, Object>();
-        props.put("prop1", "value1");
-
-        Set<String> myService = new HashSet<String>();
-        context.registerService(Set.class, myService, props);
-
-        ServiceReference serviceReference = context.bundleContext().getServiceReference(Set.class.getName());
-        Object serviceResult = context.bundleContext().getService(serviceReference);
-        assertSame(myService, serviceResult);
-        assertEquals("value1", serviceReference.getProperty("prop1"));
-    }
-
-    @Test
-    public void testRegisterMultipleServices() {
-        Set<String> myService1 = new HashSet<String>();
-        context.registerService(Set.class, myService1);
-        Set<String> myService2 = new HashSet<String>();
-        context.registerService(Set.class, myService2);
-
-        Set[] serviceResults = context.getServices(Set.class, null);
-        assertSame(myService1, serviceResults[0]);
-        assertSame(myService2, serviceResults[1]);
-    }
-
-    @Test
     public void testSetCurrentResource() {
         context.currentResource("/content/sample/en/jcr:content/par/colctrl");
         assertEquals("/content/sample/en/jcr:content/par/colctrl", context.currentResource().getPath());
@@ -178,11 +139,6 @@ public class SlingContextImplTest {
     }
 
     @Test
-    public void testRegisterInjectActivate() {
-        context.registerInjectActivateService(new Object());
-    }
-
-    @Test
     public void testRunModes() {
         SlingSettingsService slingSettings = context.getService(SlingSettingsService.class);
         assertEquals(SlingContextImpl.DEFAULT_RUN_MODES, slingSettings.getRunModes());
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/junit/SlingContextTest.java b/src/test/java/org/apache/sling/testing/mock/sling/junit/SlingContextTest.java
index 24c72dd..8af0b55 100644
--- a/src/test/java/org/apache/sling/testing/mock/sling/junit/SlingContextTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/sling/junit/SlingContextTest.java
@@ -20,14 +20,12 @@ package org.apache.sling.testing.mock.sling.junit;
 
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 
 import java.io.IOException;
 
 import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.testing.mock.sling.ResourceResolverType;
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -55,12 +53,4 @@ public class SlingContextTest {
         assertNotNull(context.request());
     }
 
-    @After
-    public void tearDown() {
-        // reset required because mockito gets puzzled with the parameterized
-        // JUnit rule
-        // TODO: better solution?
-        reset(contextSetup);
-    }
-
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 12/26: [maven-release-plugin] prepare for next development iteration

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 5dcb3d75b1ae9feb8b411f3e2aa2060d3deed4a6
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Oct 17 08:20:47 2014 +0000

    [maven-release-plugin] prepare for next development iteration
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1632503 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 26139c1..f9f16a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
     </parent>
 
     <artifactId>org.apache.sling.testing.sling-mock</artifactId>
-    <version>1.0.0</version>
+    <version>1.0.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling Testing Sling Mock</name>
@@ -39,9 +39,9 @@
     </properties>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.sling-mock-1.0.0</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.sling-mock-1.0.0</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.testing.sling-mock-1.0.0</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/testing/mocks/sling-mock</url>
     </scm>
 
     <dependencies>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 10/26: update to released versions

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 22c80249a77d0319ee0d9b583b610a91edca8cef
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Oct 17 08:19:58 2014 +0000

    update to released versions
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1632500 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pom.xml b/pom.xml
index 4fcb1cc..cf7943b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,19 +49,19 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
-            <version>1.0.0-SNAPSHOT</version>
+            <version>1.0.0</version>
             <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.jcr-mock</artifactId>
-            <version>1.0.0-SNAPSHOT</version>
+            <version>1.0.0</version>
             <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.resourceresolver-mock</artifactId>
-            <version>0.3.1-SNAPSHOT</version>
+            <version>1.0.0</version>
             <scope>compile</scope>
         </dependency>
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 05/26: SLING-4042 per default no charencoding should be set in mock response

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit e9e968a5b801e21d60638a8939a4db18b5b2e127
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Oct 15 22:03:29 2014 +0000

    SLING-4042 per default no charencoding should be set in mock response
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1632186 13f79535-47bb-0310-9956-ffa450edef68
---
 .../mock/sling/servlet/MockSlingHttpServletResponse.java       |  3 +--
 .../mock/sling/servlet/MockSlingHttpServletResponseTest.java   | 10 +++++++++-
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponse.java b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponse.java
index b5d918e..e48846f 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponse.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponse.java
@@ -26,7 +26,6 @@ import javax.servlet.ServletOutputStream;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.commons.lang3.CharEncoding;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.api.SlingHttpServletResponse;
 import org.apache.sling.api.adapter.SlingAdaptable;
@@ -39,7 +38,7 @@ public class MockSlingHttpServletResponse extends SlingAdaptable implements Slin
     private static final String CHARSET_SEPARATOR = ";charset=";
 
     private String contentType;
-    private String characterEncoding = CharEncoding.ISO_8859_1;
+    private String characterEncoding;
     private int contentLength;
     private int status = HttpServletResponse.SC_OK;
     private int bufferSize = 1024 * 8;
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponseTest.java b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponseTest.java
index e794909..944b366 100644
--- a/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponseTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponseTest.java
@@ -47,11 +47,19 @@ public class MockSlingHttpServletResponseTest {
     @Test
     public void testContentTypeCharset() throws Exception {
         assertNull(response.getContentType());
-        assertEquals(CharEncoding.ISO_8859_1, response.getCharacterEncoding());
+        assertNull(response.getCharacterEncoding());
 
+        response.setContentType("image/gif");
+        assertEquals("image/gif", response.getContentType());
+        assertNull(response.getCharacterEncoding());
+        
         response.setContentType("text/plain;charset=UTF-8");
         assertEquals("text/plain;charset=UTF-8", response.getContentType());
         assertEquals(CharEncoding.UTF_8, response.getCharacterEncoding());
+        
+        response.setCharacterEncoding(CharEncoding.ISO_8859_1);
+        assertEquals("text/plain;charset=ISO-8859-1", response.getContentType());
+        assertEquals(CharEncoding.ISO_8859_1, response.getCharacterEncoding());
     }
 
     @Test

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 17/26: SLING-4090 Define package versions for Sling Mock, JCR Mock, OSGi Mock

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 6964d497b8292aee8d6cf47d78d7952ab7edc1a5
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Oct 22 20:40:31 2014 +0000

    SLING-4090 Define package versions for Sling Mock, JCR Mock, OSGi Mock
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1633717 13f79535-47bb-0310-9956-ffa450edef68
---
 .../java/org/apache/sling/testing/mock/sling/builder/package-info.java  | 1 +
 .../java/org/apache/sling/testing/mock/sling/context/package-info.java  | 2 +-
 .../java/org/apache/sling/testing/mock/sling/junit/package-info.java    | 2 +-
 .../java/org/apache/sling/testing/mock/sling/loader/package-info.java   | 2 +-
 src/main/java/org/apache/sling/testing/mock/sling/package-info.java     | 2 +-
 .../java/org/apache/sling/testing/mock/sling/services/package-info.java | 1 +
 .../java/org/apache/sling/testing/mock/sling/servlet/package-info.java  | 2 +-
 src/main/java/org/apache/sling/testing/mock/sling/spi/package-info.java | 1 +
 8 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/sling/builder/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/builder/package-info.java
index 41f7c62..987a862 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/builder/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/builder/package-info.java
@@ -19,4 +19,5 @@
 /**
  * Content builder for creating test content.
  */
+@aQute.bnd.annotation.Version("1.0")
 package org.apache.sling.testing.mock.sling.builder;
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/context/package-info.java
index e229f1e..ca62fc4 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/context/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/package-info.java
@@ -19,5 +19,5 @@
 /**
  * Sling context implementation for unit tests.
  */
+@aQute.bnd.annotation.Version("1.0")
 package org.apache.sling.testing.mock.sling.context;
-
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/junit/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/junit/package-info.java
index d30c3d0..4700e5a 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/junit/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/junit/package-info.java
@@ -19,5 +19,5 @@
 /**
  * Rule for providing easy access to Sling context in JUnit tests.
  */
+@aQute.bnd.annotation.Version("1.0")
 package org.apache.sling.testing.mock.sling.junit;
-
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java
index ebe7af5..464320c 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java
@@ -19,5 +19,5 @@
 /**
  * Helpers for importing test content into the mocked repositories / resource hierarchies.
  */
+@aQute.bnd.annotation.Version("1.0")
 package org.apache.sling.testing.mock.sling.loader;
-
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/package-info.java
index 5919826..7b9feaa 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/package-info.java
@@ -19,5 +19,5 @@
 /**
  * Mock implementation of selected Sling APIs.
  */
+@aQute.bnd.annotation.Version("1.0")
 package org.apache.sling.testing.mock.sling;
-
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/services/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/services/package-info.java
index 6267725..83ecb71 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/services/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/services/package-info.java
@@ -19,4 +19,5 @@
 /**
  * Mocks for selected Sling services.
  */
+@aQute.bnd.annotation.Version("1.0")
 package org.apache.sling.testing.mock.sling.services;
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/servlet/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/servlet/package-info.java
index 389e6ec..be537b4 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/servlet/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/servlet/package-info.java
@@ -19,5 +19,5 @@
 /**
  * Mock implementation of selected Servlet-related Sling APIs.
  */
+@aQute.bnd.annotation.Version("1.1")
 package org.apache.sling.testing.mock.sling.servlet;
-
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/spi/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/spi/package-info.java
index 082a28a..0316d03 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/spi/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/spi/package-info.java
@@ -19,4 +19,5 @@
 /**
  * SPI for hooking in alternative resource type adapter implementations.
  */
+@aQute.bnd.annotation.Version("1.0")
 package org.apache.sling.testing.mock.sling.spi;

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 06/26: SLING-4042 do not forget to register ResourceResolverFactory in OSGi context as well

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 43eb3508bbf6ca3fa5919e39173ceacf1da14c7e
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Thu Oct 16 16:11:32 2014 +0000

    SLING-4042 do not forget to register ResourceResolverFactory in OSGi context as well
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1632375 13f79535-47bb-0310-9956-ffa450edef68
---
 .../context/ContextResourceResolverFactory.java    | 29 ++++++++++++----------
 .../mock/sling/context/SlingContextImpl.java       | 24 ++++++++++++++----
 .../mock/sling/context/SlingContextImplTest.java   |  7 ++++++
 3 files changed, 42 insertions(+), 18 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java b/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java
index a8596ae..2891fc6 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java
@@ -22,7 +22,9 @@ import javax.jcr.NamespaceRegistry;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
+import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.testing.mock.sling.MockSling;
 import org.apache.sling.testing.mock.sling.ResourceResolverType;
 
@@ -35,42 +37,43 @@ final class ContextResourceResolverFactory {
         // static methods only
     }
 
-    public static ResourceResolver initializeResourceResolver(final ResourceResolverType resourceResolverType) {
+    public static ResourceResolverFactory get(final ResourceResolverType resourceResolverType) {
         try {
-            ResourceResolver resourceResolver = MockSling.newResourceResolver(resourceResolverType);
+            ResourceResolverFactory factory = MockSling.newResourceResolverFactory(resourceResolverType);
 
             switch (resourceResolverType) {
             case JCR_MOCK:
-                initializeJcrMock(resourceResolver);
+                initializeJcrMock(factory);
                 break;
             case JCR_JACKRABBIT:
-                initializeJcrJackrabbit(resourceResolver);
+                initializeJcrJackrabbit(factory);
                 break;
             case RESOURCERESOLVER_MOCK:
-                initializeResourceResolverMock(resourceResolver);
+                initializeResourceResolverMock(factory);
                 break;
             default:
                 throw new IllegalArgumentException("Invalid resource resolver type: " + resourceResolverType);
             }
 
-            return resourceResolver;
+            return factory;
         } catch (Throwable ex) {
-            throw new RuntimeException("Unable to initialize " + resourceResolverType + " resource resolver.", ex);
+            throw new RuntimeException("Unable to initialize " + resourceResolverType + " resource resolver factory.", ex);
         }
     }
 
-    private static void initializeJcrMock(final ResourceResolver resourceResolver) throws RepositoryException {
+    private static void initializeJcrMock(ResourceResolverFactory factory) throws RepositoryException, LoginException {
         // register default namespaces
-        NamespaceRegistry namespaceRegistry = resourceResolver.adaptTo(Session.class).getWorkspace()
-                .getNamespaceRegistry();
+        ResourceResolver resolver = factory.getResourceResolver(null);
+        Session session = resolver.adaptTo(Session.class);
+        NamespaceRegistry namespaceRegistry = session.getWorkspace().getNamespaceRegistry();
         namespaceRegistry.registerNamespace("sling", "http://sling.apache.org/jcr/sling/1.0");
     }
 
-    private static void initializeJcrJackrabbit(final ResourceResolver resourceResolver) {
-        // TODO: register sling node types
+    private static void initializeJcrJackrabbit(ResourceResolverFactory factory) {
+        // register sling node types?
     }
 
-    private static void initializeResourceResolverMock(final ResourceResolver resourceResolver) {
+    private static void initializeResourceResolverMock(ResourceResolverFactory factory) {
         // nothing to do
     }
 
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java b/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
index d72434d..907f804 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
@@ -27,8 +27,10 @@ import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
 import org.apache.sling.api.adapter.AdapterFactory;
+import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.api.scripting.SlingBindings;
 import org.apache.sling.api.scripting.SlingScriptHelper;
 import org.apache.sling.commons.mime.MimeTypeService;
@@ -73,6 +75,7 @@ public class SlingContextImpl {
     // default to publish instance run mode
     static final Set<String> DEFAULT_RUN_MODES = ImmutableSet.<String> builder().add("publish").build();
 
+    protected ResourceResolverFactory resourceResolverFactory;
     protected MockModelAdapterFactory modelAdapterFactory;
     protected ResourceResolverType resourceResolverType;
     protected ComponentContext componentContext;
@@ -95,14 +98,25 @@ public class SlingContextImpl {
      */
     protected void setUp() {
         MockSling.setAdapterManagerBundleContext(bundleContext());
+        this.resourceResolverFactory = newResourceResolverFactory();
         registerDefaultServices();
     }
+    
+    /**
+     * Initialize mocked resource resolver factory.
+     */
+    protected ResourceResolverFactory newResourceResolverFactory() {
+        return ContextResourceResolverFactory.get(this.resourceResolverType);
+    }
 
     /**
      * Default services that should be available for every unit test
      */
     protected void registerDefaultServices() {
 
+        // resource resolver factory
+        registerService(ResourceResolverFactory.class, this.resourceResolverFactory);
+        
         // adapter factories
         modelAdapterFactory = new MockModelAdapterFactory(componentContext());
         registerService(AdapterFactory.class, modelAdapterFactory);
@@ -187,15 +201,15 @@ public class SlingContextImpl {
      */
     public final ResourceResolver resourceResolver() {
         if (this.resourceResolver == null) {
-            this.resourceResolver = createMockResourceResolver();
+            try {
+                this.resourceResolver = this.resourceResolverFactory.getResourceResolver(null);
+            } catch (LoginException ex) {
+                throw new RuntimeException("Creating resource resolver failed.", ex);
+            }
         }
         return this.resourceResolver;
     }
     
-    protected ResourceResolver createMockResourceResolver() {
-        return ContextResourceResolverFactory.initializeResourceResolver(resourceResolverType());
-    }
-
     /**
      * @return Sling request
      */
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java b/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java
index eed2ec6..d667002 100644
--- a/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java
@@ -34,6 +34,7 @@ import javax.inject.Inject;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.api.scripting.SlingBindings;
 import org.apache.sling.commons.mime.MimeTypeService;
 import org.apache.sling.models.annotations.Model;
@@ -192,6 +193,12 @@ public class SlingContextImplTest {
         assertTrue(newRunModes.contains("mode1"));
         assertTrue(newRunModes.contains("mode2"));
     }
+    
+    @Test
+    public void testResourceResolverFactory() {
+        ResourceResolverFactory factory = context.getService(ResourceResolverFactory.class);
+        assertNotNull(factory);
+    }
 
     @Model(adaptables = SlingHttpServletRequest.class)
     public interface RequestAttributeModel {

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 22/26: SLING-4108 default to getAdministrativeResourceResolver in sling-mock to support jackrabbit resource resolver adapter as well

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit a07abf84ec5d6c816b636d3ef40f147891306691
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Dec 9 13:14:58 2014 +0000

    SLING-4108 default to getAdministrativeResourceResolver in sling-mock to support jackrabbit resource resolver adapter as well
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1644043 13f79535-47bb-0310-9956-ffa450edef68
---
 src/main/java/org/apache/sling/testing/mock/sling/MockSling.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/sling/MockSling.java b/src/main/java/org/apache/sling/testing/mock/sling/MockSling.java
index 208a8d1..5b7ca82 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/MockSling.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/MockSling.java
@@ -109,7 +109,7 @@ public final class MockSling {
     public static ResourceResolver newResourceResolver(final ResourceResolverType type) {
         ResourceResolverFactory factory = newResourceResolverFactory(type);
         try {
-            return factory.getResourceResolver(null);
+            return factory.getAdministrativeResourceResolver(null);
         } catch (LoginException ex) {
             throw new RuntimeException("Mock resource resolver factory implementation seems to require login.", ex);
         }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 26/26: [maven-release-plugin] copy for tag org.apache.sling.testing.sling-mock-1.1.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 6687d06e53344138ae818d681c3767f53b46d17f
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Dec 9 23:06:43 2014 +0000

    [maven-release-plugin]  copy for tag org.apache.sling.testing.sling-mock-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.sling-mock-1.1.0@1644230 13f79535-47bb-0310-9956-ffa450edef68

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 03/26: SLING-4042 move all mock projects to mocks/ subdirectory

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit a6e7c1a84902e7c990c482c3361fc0ec3a63275a
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Mon Oct 13 14:32:45 2014 +0000

    SLING-4042 move all mock projects to mocks/ subdirectory
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1631416 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                      |   2 +-
 src/site/markdown/index.md                   |  67 --------------
 src/site/markdown/resource-resolver-types.md |  53 -----------
 src/site/markdown/usage-content-loader.md    |  59 ------------
 src/site/markdown/usage-mocks.md             | 130 ---------------------------
 5 files changed, 1 insertion(+), 310 deletions(-)

diff --git a/pom.xml b/pom.xml
index d4ce536..f314611 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
         <groupId>org.apache.sling</groupId>
         <artifactId>sling</artifactId>
         <version>22</version>
-        <relativePath>../../parent/pom.xml</relativePath>
+        <relativePath>../../../parent/pom.xml</relativePath>
     </parent>
 
     <artifactId>org.apache.sling.testing.sling-mock</artifactId>
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
deleted file mode 100644
index 407ab8b..0000000
--- a/src/site/markdown/index.md
+++ /dev/null
@@ -1,67 +0,0 @@
-## About Sling Mocks
-
-Mock implementation of selected Sling APIs.
-
-
-### Maven Dependency
-
-```xml
-<dependency>
-  <groupId>org.apache.sling</groupId>
-  <artifactId>org.apache.sling.testing.sling-mock</artifactId>
-  <version>1.0.0-SNAPHOT</version>
-</dependency>
-```
-
-### Documentation
-
-* [Sling Mocks Usage][usage-mocks]
-* [Content Loader Usage][usage-content-loader]
-* [API Documentation][apidocs]
-* [Changelog][changelog]
-
-
-### Implemented mock features
-
-The mock implementation supports:
-
-* `ResourceResolver` implementation for reading and writing resource data using the Sling Resource API
-    * Backed by a [mocked][jcr-mock] or real Jackrabbit JCR implementation
-    * Uses the productive [Sling JCR resource provider implementation][jcr-resource] internally to do the Resource-JCR mapping
-    * Alternatively the non-JCR mock implementation provided by the 
-   [Sling resourceresolver-mock implementation][resourceresolver-mock] can be used
-* `AdpaterManager` implementation for registering adapter factories and resolving adaptions
-    * The implementation is thread-safe so it can be used in parallel running unit tests
-* `SlingScriptHelper` implementation providing access to mocked request/response objects and supports getting
-   OSGi services from the [mocked OSGi][osgi-mock] environment.
-* Implementations of the servlet-related Sling API classes like `SlingHttpServletRequest` and `SlingHttpServletRequest`
-    * It is possible to set request data to simulate a certian Sling HTTP request
-* Additional services like `MockModelAdapterFactory` and  `MimeTypeService` 
-
-[osgi-mock]: http://sling.apache.org/testing/osgi-mock/
-[jcr-mock]: http://sling.apache.org/testing/jcr-mock/
-[jcr-resource]: http://svn.apache.org/repos/asf/sling/trunk/bundles/jcr/resource
-[resourceresolver-mock]: http://svn.eu.apache.org/repos/asf/sling/trunk/testing/resourceresolver-moc
-
-The following features are *not supported*:
-
-* It is not possible (nor intended) to really execute sling components/scripts and render their results.
-    * The goal is to test supporting classes in Sling context, not the sling components/scripts themselves
-
-See [Sling Mocks Usage][usage-mocks].
-
-
-### Additional features
-
-Additional features provided:
-
-* `ContentLoader` supports importing JSON data and binary data into the mock resource hierarchy to easily 
-  prepare a test fixture consisting of a hierarchy of resources and properties.
-    * The same JSON format can be used that is provided by the Sling GET servlet for output
-
-See [Content Loader Usage][usage-content-loader].
-
-[usage-mocks]: usage-mocks.html
-[usage-content-loader]: usage-content-loader.html
-[apidocs]: apidocs/
-[changelog]: changes-report.html
diff --git a/src/site/markdown/resource-resolver-types.md b/src/site/markdown/resource-resolver-types.md
deleted file mode 100644
index 3cacb49..0000000
--- a/src/site/markdown/resource-resolver-types.md
+++ /dev/null
@@ -1,53 +0,0 @@
-## Resource Resolver Types
-
-The Sling Mocks resource resolver implementation supports different "types" of adapters for the mocks.
-Depending on the type an underlying JCR repository is used or not, and the data ist stored in-memory or in a real 
-repository.
-
-This pages lists all resource resolver types currently supported.
-
-### RESOURCERESOLVER_MOCK (default)
-
-* Simulates an In-Memory resource tree, does not provide adaptions to JCR API.
-* Based on the [Sling resourceresolver-mock implementation][resourceresolver-mock] implementation
-* You can use it to make sure the code you want to test does not contain references to JCR API.
-* Behaves slightly different from JCR resource mapping e.g. handling binary and date values.
-* This resource resolver type is very fast because data is stored in memory and no JCR mapping is applied.
-
-### JCR_MOCK
-
-* Based on the [JCR Mocks][jcr-mock] implementation
-* Uses the productive [Sling JCR resource provider implementation][jcr-resource] internally to do the Resource-JCR mapping
-* Is quite fast because data is stored only in-memory
-
-### JCR_JACKRABBIT
-
-* Uses a real JCR Jackrabbit implementation (not Oak) as provided by [sling/commons/testing][sling-comons-testing]
-* Full JCR/Sling features supported e.g. observations manager, transactions, versioning
-* Uses the productive [Sling JCR resource provider implementation][jcr-resource] internally to do the Resource-JCR mapping
-* Takes some seconds for startup on the first access 
-* All node types that are used when reading/writing data have to be registered
-
-_Warnings/Remarks_
-
-* The repository is not cleared for each unit test, so make sure us use a unique node path for each unit test.
-* To import Sling content you have to fully register all node types required for the data
-* The [sling/commons/testing][sling-comons-testing] dependency introduces a lot of further dependencies from
-  jackrabbit and others, be careful that they do not conflict and are imported in the right order in your test project
-
-To use this type you have to declare an additional dependency in your test project:
-
-```xml
-<dependency>
-  <groupId>org.apache.sling</groupId>
-  <artifactId>org.apache.sling.testing.sling-mock-jackrabbit</artifactId>
-  <version>1.0.0-SNAPHOT</version>
-  <scope>test</scope>
-</dependency>
-```
-
-
-[jcr-mock]: http://sling.apache.org/testing/jcr-mock/
-[jcr-resource]: http://svn.apache.org/repos/asf/sling/trunk/bundles/jcr/resource
-[resourceresolver-mock]: http://svn.eu.apache.org/repos/asf/sling/trunk/testing/resourceresolver-moc
-[sling-comons-testing]: http://svn.apache.org/repos/asf/sling/trunk/bundles/commons/testing
diff --git a/src/site/markdown/usage-content-loader.md b/src/site/markdown/usage-content-loader.md
deleted file mode 100644
index 8d88146..0000000
--- a/src/site/markdown/usage-content-loader.md
+++ /dev/null
@@ -1,59 +0,0 @@
-## Usage
-
-### Import resource data from JSON file in classpath
-
-With the `ContentLoader` it is possible to import structured resource and property data from a JSON file stored
-in the classpath beneath the unit tests. This data can be used as text fixture for unit tests.
-
-Example JSON data:
-
-```json
-{
-  "jcr:primaryType": "app:Page",
-  "jcr:content": {
-    "jcr:primaryType": "app:PageContent",
-    "jcr:title": "English",
-    "app:template": "/apps/sample/templates/homepage",
-    "sling:resourceType": "sample/components/homepage",
-    "jcr:createdBy": "admin",
-    "jcr:created": "Thu Aug 07 2014 16:32:59 GMT+0200",
-    "par": {
-      "jcr:primaryType": "nt:unstructured",
-      "sling:resourceType": "foundation/components/parsys",
-      "colctrl": {
-        "jcr:primaryType": "nt:unstructured",
-        "layout": "2;colctrl-lt0",
-        "sling:resourceType": "foundation/components/parsys/colctrl"
-      }
-    }
-  }
-}
-```
-
-Example code to import the JSON data:
-
-```java
-ResourceResolver resolver = MockSling.newResourceResolver();
-ContentLoader contentLoader = new ContentLoader(resolver);
-contentLoader.json("/sample-data.json", "/content/sample/en");
-```
-
-This codes creates a new resource at `/content/sample/en` (and - if not existent - the parent resources) and
-imports the JSON data to this node. It can be accessed using the Sling Resource or JCR API afterwards.
-
-
-### Import binary data from file in classpath
-
-With the `ContentLoader` it is possible to import a binary file stored in the classpath beneath the unit tests.
-The data is stored usig a nt:file/nt:resource or nt:resource node type. 
-
-Example code to import a binary file:
-
-```java
-ResourceResolver resolver = MockSling.newResourceResolver();
-ContentLoader contentLoader = new ContentLoader(resolver);
-contentLoader.binaryFile("/sample-file.gif", "/content/binary/sample-file.gif");
-```
-
-This codes creates a new resource at `/content/binary/sample-file.gif` (and - if not existent - the parent 
-resources) and imports the binary data to a jcr:content subnode.
diff --git a/src/site/markdown/usage-mocks.md b/src/site/markdown/usage-mocks.md
deleted file mode 100644
index a942c09..0000000
--- a/src/site/markdown/usage-mocks.md
+++ /dev/null
@@ -1,130 +0,0 @@
-## Usage
-
-The factory class `MockSling` allows to instantiate the different mock implementations.
-
-### Sling Resource Resolver
-
-Example:
-
-```java
-// get a resource resolver
-ResourceResolver resolver = MockSling.newResourceResolver();
-
-// get a resource resolver backed by a specific repository type
-ResourceResolver resolver = MockSling.newResourceResolver(ResourceResolverType.JCR_MOCK);
-```
-The following types are supported currently: [Resource Resolver Types](resource-resolver-types.html)
-
-### Adapter Factories
-
-You can register your own or existing adapter factories to support adaptions e.g. for classes extending `SlingAdaptable`.
-
-Example:
-
-```java
-// register adapter factory
-BundleContext bundleContext = MockOsgi.newBundleContext();
-MockSling.setAdapterManagerBundleContext(bundleContext);
-bundleContext.registerService(myAdapterFactory);
-
-// test adaption
-MyClass object = resource.adaptTo(MyClass.class);
-
-// cleanup after unit test
-MockSling.clearAdapterManagerBundleContext();
-```
-
-Make sure you clean up the adapter manager bundle association after running the unit test otherwise it can 
-interfere with the following tests. If you use the `SlingContext` Junit rule this is done automatically for you.
-
-
-### SlingScriptHelper
-
-Example:
-
-```java
-// get script helper
-SlingScriptHelper scriptHelper = MockSling.newSlingScriptHelper();
-
-// get request
-SlingHttpServletRequest request = scriptHelper.getRequest();
-
-// get service
-MyService object = scriptHelper.getService(MyService.class);
-```
-
-To support getting OSGi services you have to register them via the `BundleContext` interface of the
-[JCR Mocks][jcr-mock] before. You can use an alternative factory method for the `SlingScriptHelper` providing
-existing instances of request, response and bundle context. 
-
-
-### SlingHttpServletRequest
-
-Example for preparing a sling request with custom request data:
-
-```java
-// prepare sling request
-ResourceResolver resourceResolver = MockSling.newResourceResolver();
-MockSlingHttpServletRequest request = new MockSlingHttpServletRequest(resourceResolver);
-
-// simulate query string
-request.setQueryString("param1=aaa&param2=bbb");
-
-// alternative - set query parameters as map
-request.setParameterMap(ImmutableMap.<String,Object>builder()
-    .put("param1", "aaa")
-    .put("param2", "bbb")
-    .build());
-
-// set current resource
-request.setResource(resourceResolver.getResource("/content/sample"));
-
-// set sling request path info properties
-MockRequestPathInfo requestPathInfo = (MockRequestPathInfo)request.getRequestPathInfo();
-requestPathInfo.setSelectorString("selector1.selector2");
-requestPathInfo.setExtension("html");
-
-// set method
-request.setMethod(HttpConstants.METHOD_POST);
-
-// set attributes
-request.setAttribute("attr1", "value1");
-
-// set headers
-request.addHeader("header1", "value1");
-
-// set cookies
-request.addCookie(new Cookie("cookie1", "value1"));
-```
-
-### SlingHttpServletResponse
-
-Example for preparing a sling response which can collect the data that was written to it:
-
-```java
-// prepare sling response
-MockSlingHttpServletResponse response = new MockSlingHttpServletResponse();
-
-// execute your unit test code that writes to the response...
-
-// validate status code
-assertEquals(HttpServletResponse.SC_OK, response.getStatus());
-
-// validate content type and content length
-assertEquals("text/plain;charset=UTF-8", response.getContentType());
-assertEquals(CharEncoding.UTF_8, response.getCharacterEncoding());
-assertEquals(55, response.getContentLength());
-
-// validate headers
-assertTrue(response.containsHeader("header1"));
-assertEquals("5", response.getHeader("header2"));
-
-// validate response body as string
-assertEquals(TEST_CONTENT, response.getOutputAsString());
-
-// validate response body as binary data
-assertArrayEquals(TEST_DATA, response.getOutput());
-```
-
-
-[jcr-mock]: http://sling.apache.org/testing/jcr-mock/

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 01/26: SLING-4042 Donate sling-mock, jcr-mock, osgi-mock implementation

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 2aa4712721ccad034be2a252aaf30fbd7cf5dbc3
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Mon Oct 13 11:54:39 2014 +0000

    SLING-4042 Donate sling-mock, jcr-mock, osgi-mock implementation
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/sling-mock@1631356 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            | 240 +++++++
 .../mock/sling/JcrMockResourceResolverAdapter.java |  44 ++
 .../testing/mock/sling/MockAdapterManager.java     |  81 +++
 .../mock/sling/MockJcrResourceResolverFactory.java | 117 ++++
 .../MockResourceResolverFactoryActivator.java      |  52 ++
 .../apache/sling/testing/mock/sling/MockSling.java | 167 +++++
 .../testing/mock/sling/MockSlingRepository.java    | 112 ++++
 .../testing/mock/sling/MockSlingScriptHelper.java  | 163 +++++
 .../sling/RRMockMockResourceResolverAdapter.java   |  52 ++
 .../testing/mock/sling/ResourceResolverType.java   |  86 +++
 .../sling/ThreadsafeMockAdapterManagerWrapper.java |  61 ++
 .../testing/mock/sling/builder/ContentBuilder.java | 108 ++++
 .../testing/mock/sling/builder/package-info.java   |  22 +
 .../context/ContextResourceResolverFactory.java    |  77 +++
 .../mock/sling/context/SlingContextImpl.java       | 401 ++++++++++++
 .../testing/mock/sling/context/package-info.java   |  23 +
 .../testing/mock/sling/junit/SlingContext.java     | 207 ++++++
 .../mock/sling/junit/SlingContextCallback.java     |  37 ++
 .../testing/mock/sling/junit/package-info.java     |  23 +
 .../testing/mock/sling/loader/ContentLoader.java   | 586 +++++++++++++++++
 .../testing/mock/sling/loader/package-info.java    |  23 +
 .../sling/testing/mock/sling/package-info.java     |  23 +
 .../mock/sling/services/MockMimeTypeService.java   |  78 +++
 .../sling/services/MockModelAdapterFactory.java    | 295 +++++++++
 .../sling/services/MockSlingSettingService.java    |  90 +++
 .../testing/mock/sling/servlet/CookieSupport.java  |  53 ++
 .../testing/mock/sling/servlet/HeaderSupport.java  | 175 ++++++
 .../mock/sling/servlet/MockHttpSession.java        | 129 ++++
 .../mock/sling/servlet/MockRequestPathInfo.java    |  86 +++
 .../mock/sling/servlet/MockServletContext.java     | 301 +++++++++
 .../sling/servlet/MockSlingHttpServletRequest.java | 696 +++++++++++++++++++++
 .../servlet/MockSlingHttpServletResponse.java      | 280 +++++++++
 .../mock/sling/servlet/ResponseBodySupport.java    |  93 +++
 .../testing/mock/sling/servlet/package-info.java   |  23 +
 .../sling/spi/ResourceResolverTypeAdapter.java     |  46 ++
 src/site/markdown/index.md                         |  67 ++
 src/site/markdown/resource-resolver-types.md       |  53 ++
 src/site/markdown/usage-content-loader.md          |  59 ++
 src/site/markdown/usage-mocks.md                   | 130 ++++
 .../testing/mock/sling/MockAdapterManagerTest.java |  69 ++
 .../mock/sling/MockSlingRepositoryTest.java        |  46 ++
 .../mock/sling/MockSlingScriptHelperTest.java      |  79 +++
 .../mock/sling/builder/ContentBuilderTest.java     |  61 ++
 .../mock/sling/context/SlingContextImplTest.java   | 224 +++++++
 .../jcrmock/loader/ContentLoaderBinaryTest.java    |  33 +
 .../jcrmock/loader/ContentLoaderJsonDamTest.java   |  30 +
 .../jcrmock/loader/ContentLoaderJsonTest.java      |  30 +
 .../jcrmock/resource/JcrResourceResolverTest.java  |  34 +
 .../resource/SlingCrudResourceResolverTest.java    |  34 +
 .../testing/mock/sling/junit/SlingContextTest.java |  66 ++
 .../loader/AbstractContentLoaderBinaryTest.java    | 121 ++++
 .../loader/AbstractContentLoaderJsonDamTest.java   |  85 +++
 .../loader/AbstractContentLoaderJsonTest.java      | 182 ++++++
 .../resource/AbstractJcrResourceResolverTest.java  | 168 +++++
 .../AbstractSlingCrudResourceResolverTest.java     | 214 +++++++
 .../rrmock/loader/ContentLoaderBinaryTest.java     |  38 ++
 .../rrmock/loader/ContentLoaderJsonDamTest.java    |  38 ++
 .../sling/rrmock/loader/ContentLoaderJsonTest.java |  38 ++
 .../resource/SlingCrudResourceResolverTest.java    |  38 ++
 .../sling/services/MockMimeTypeServiceTest.java    |  51 ++
 .../services/MockModelAdapterFactoryTest.java      | 142 +++++
 .../services/MockSlingSettingServiceTest.java      |  53 ++
 .../mock/sling/servlet/MockHttpSessionTest.java    |  74 +++
 .../sling/servlet/MockRequestPathInfoTest.java     |  68 ++
 .../mock/sling/servlet/MockServletContextTest.java |  42 ++
 .../servlet/MockSlingHttpServletRequestTest.java   | 216 +++++++
 .../servlet/MockSlingHttpServletResponseTest.java  | 168 +++++
 .../resources/json-import-samples/content.json     | 257 ++++++++
 src/test/resources/json-import-samples/dam.json    | 156 +++++
 src/test/resources/sample-image.gif                | Bin 0 -> 62 bytes
 70 files changed, 8214 insertions(+)

diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..d4ce536
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,240 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  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/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>22</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.sling.testing.sling-mock</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>Apache Sling Testing Sling Mock</name>
+    <description>Mock implementation of selected Sling APIs.</description>
+
+    <properties>
+        <sling.java.version>6</sling.java.version>
+    </properties>
+
+    <dependencies>
+  
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
+            <version>1.0.0-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.testing.jcr-mock</artifactId>
+            <version>1.0.0-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.testing.resourceresolver-mock</artifactId>
+            <version>0.3.1-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.models.api</artifactId>
+            <version>1.1.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.models.impl</artifactId>
+            <version>1.1.0</version>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.api</artifactId>
+            <version>2.4.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.resourceresolver</artifactId>
+            <version>1.1.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.jcr.api</artifactId>
+            <version>2.2.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.jcr.resource</artifactId>
+            <version>2.3.6</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.mime</artifactId>
+            <version>2.1.4</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.json</artifactId>
+            <version>2.0.6</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.osgi</artifactId>
+            <version>2.2.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.classloader</artifactId>
+            <version>1.3.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.settings</artifactId>
+            <version>1.2.2</version>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
+            <version>3.2.1</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+            <version>2.5</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+            <version>1.8.3</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.reflections</groupId>
+            <artifactId>reflections</artifactId>
+            <version>0.9.9-RC2</version>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>org.mortbay.jetty</groupId>
+            <artifactId>servlet-api</artifactId>
+            <version>3.0.20100224</version>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>javax.inject</groupId>
+            <artifactId>javax.inject</artifactId>
+            <version>1</version>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>javax.jcr</groupId>
+            <artifactId>jcr</artifactId>
+            <version>2.0</version>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>1.9.5</version>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+  
+    <build>
+        <plugins>
+    
+          <!-- Publish test artifact -->
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-jar-plugin</artifactId>
+            <executions>
+              <execution>
+                <goals>
+                  <goal>test-jar</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+    
+          <plugin>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>maven-bundle-plugin</artifactId>
+            <extensions>true</extensions>
+          </plugin>
+    
+          <plugin>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>maven-scr-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>generate-scr-scrdescriptor</id>
+                <goals>
+                  <goal>scr</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+    
+        </plugins>
+    </build>
+  
+</project>
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/JcrMockResourceResolverAdapter.java b/src/main/java/org/apache/sling/testing/mock/sling/JcrMockResourceResolverAdapter.java
new file mode 100644
index 0000000..6aafe5d
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/JcrMockResourceResolverAdapter.java
@@ -0,0 +1,44 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling;
+
+import javax.jcr.Repository;
+
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.testing.mock.jcr.MockJcr;
+import org.apache.sling.testing.mock.sling.spi.ResourceResolverTypeAdapter;
+
+/**
+ * Resource resolver type adapter for JCR Mocks implementation.
+ */
+class JcrMockResourceResolverAdapter implements ResourceResolverTypeAdapter {
+
+    @Override
+    public ResourceResolverFactory newResourceResolverFactory() {
+        return null;
+    }
+
+    @Override
+    public SlingRepository newSlingRepository() {
+        Repository repository = MockJcr.newRepository();
+        return new MockSlingRepository(repository);
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/MockAdapterManager.java b/src/main/java/org/apache/sling/testing/mock/sling/MockAdapterManager.java
new file mode 100644
index 0000000..60b2082
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/MockAdapterManager.java
@@ -0,0 +1,81 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling;
+
+import org.apache.sling.api.adapter.AdapterFactory;
+import org.apache.sling.api.adapter.AdapterManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Mock {@link AdapterManager} implementation.
+ */
+class MockAdapterManager implements AdapterManager {
+
+    /**
+     * OSGi bundle context to detect all services that implement
+     * {@link AdapterFactory}.
+     */
+    private BundleContext bundleContext;
+
+    /**
+     * Returns the adapted <code>adaptable</code> or <code>null</code> if the
+     * object cannot be adapted.
+     */
+    @Override
+    public <AdapterType> AdapterType getAdapter(final Object adaptable, final Class<AdapterType> type) {
+
+        // iterate over all adapter factories and try to adapt the object
+        if (this.bundleContext != null) {
+            try {
+                ServiceReference[] references = bundleContext
+                        .getServiceReferences(AdapterFactory.class.getName(), null);
+                for (ServiceReference serviceReference : references) {
+                    AdapterFactory adapterFactory = (AdapterFactory) bundleContext.getService(serviceReference);
+                    AdapterType instance = adapterFactory.getAdapter(adaptable, type);
+                    if (instance != null) {
+                        return instance;
+                    }
+                }
+            } catch (InvalidSyntaxException ex) {
+                throw new RuntimeException("Unable to get adapter factories.", ex);
+            }
+        }
+
+        // no matching adapter factory found
+        return null;
+    }
+
+    /**
+     * Sets bundle context.
+     * @param bundleContext Bundle context
+     */
+    public void setBundleContext(final BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    /**
+     * Removes bundle context reference.
+     */
+    public void clearBundleContext() {
+        this.bundleContext = null;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/MockJcrResourceResolverFactory.java b/src/main/java/org/apache/sling/testing/mock/sling/MockJcrResourceResolverFactory.java
new file mode 100644
index 0000000..8a9716b
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/MockJcrResourceResolverFactory.java
@@ -0,0 +1,117 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.jcr.resource.internal.helper.jcr.JcrResourceProviderFactory;
+import org.apache.sling.resourceresolver.impl.CommonResourceResolverFactoryImpl;
+import org.apache.sling.resourceresolver.impl.ResourceAccessSecurityTracker;
+import org.apache.sling.resourceresolver.impl.ResourceResolverImpl;
+import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Mock {@link ResourceResolver} implementation. Simulates OSGi environment and
+ * intatiates real Sling ResourceResolver and JCR implementation, but with a
+ * mocked JCR repository implementation underneath.
+ */
+class MockJcrResourceResolverFactory implements ResourceResolverFactory {
+
+    private final SlingRepository slingRepository;
+
+    public MockJcrResourceResolverFactory(final SlingRepository repository) {
+        this.slingRepository = repository;
+    }
+
+    @Override
+    public ResourceResolver getResourceResolver(final Map<String, Object> authenticationInfo) throws LoginException {
+        // setup mock OSGi environment
+        Dictionary<String, Object> resourceProviderFactoryProps = new Hashtable<String, Object>();
+        resourceProviderFactoryProps.put(Constants.SERVICE_VENDOR, "sling-mock");
+        resourceProviderFactoryProps.put(Constants.SERVICE_DESCRIPTION, "sling-mock");
+        resourceProviderFactoryProps.put("resource.resolver.manglenamespaces", true);
+        ComponentContext componentContext = MockOsgi.newComponentContext(resourceProviderFactoryProps);
+
+        // setup mocked JCR environment
+        componentContext.getBundleContext()
+                .registerService(SlingRepository.class.getName(), this.slingRepository, null);
+
+        // setup real sling JCR resource provider implementation for use in
+        // mocked context
+        JcrResourceProviderFactory jcrResourceProviderFactory = new JcrResourceProviderFactory();
+        MockOsgi.injectServices(jcrResourceProviderFactory, componentContext.getBundleContext());
+        MockOsgi.activate(jcrResourceProviderFactory, componentContext.getBundleContext(),
+                ImmutableMap.<String, Object> of());
+        ResourceProvider resourceProvider = jcrResourceProviderFactory
+                .getAdministrativeResourceProvider(new HashMap<String, Object>());
+        Dictionary<Object, Object> resourceProviderProps = new Hashtable<Object, Object>();
+        resourceProviderProps.put(ResourceProvider.ROOTS, new String[] { "/" });
+        componentContext.getBundleContext().registerService(ResourceProvider.class.getName(), resourceProvider,
+                resourceProviderProps);
+        ServiceReference resourceProviderServiceReference = componentContext.getBundleContext().getServiceReference(
+                ResourceProvider.class.getName());
+
+        // setup real sling resource resolver implementation for use in mocked
+        // context
+        MockResourceResolverFactoryActivator activator = new MockResourceResolverFactoryActivator();
+        activator.bindResourceProvider(resourceProvider,
+                getServiceReferenceProperties(resourceProviderServiceReference));
+        activator.activate(componentContext);
+        CommonResourceResolverFactoryImpl commonFactoryImpl = new CommonResourceResolverFactoryImpl(activator);
+        ResourceResolverContext context = new ResourceResolverContext(true, null, new ResourceAccessSecurityTracker());
+        ResourceResolverImpl resourceResolver = new ResourceResolverImpl(commonFactoryImpl, context);
+        return resourceResolver;
+    }
+
+    private Map<String, Object> getServiceReferenceProperties(final ServiceReference serviceReference) {
+        Map<String, Object> props = new HashMap<String, Object>();
+        String[] keys = serviceReference.getPropertyKeys();
+        for (String key : keys) {
+            props.put(key, serviceReference.getProperty(key));
+        }
+        return props;
+    }
+
+    @Override
+    public ResourceResolver getAdministrativeResourceResolver(final Map<String, Object> authenticationInfo)
+            throws LoginException {
+        return getResourceResolver(authenticationInfo);
+    }
+
+    // part of Sling API 2.7
+    public ResourceResolver getServiceResourceResolver(final Map<String, Object> authenticationInfo)
+            throws LoginException {
+        return getResourceResolver(authenticationInfo);
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/MockResourceResolverFactoryActivator.java b/src/main/java/org/apache/sling/testing/mock/sling/MockResourceResolverFactoryActivator.java
new file mode 100644
index 0000000..12dc624
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/MockResourceResolverFactoryActivator.java
@@ -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.
+ */
+package org.apache.sling.testing.mock.sling;
+
+import java.util.Map;
+
+import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.api.resource.ResourceProviderFactory;
+import org.apache.sling.resourceresolver.impl.ResourceResolverFactoryActivator;
+import org.osgi.service.component.ComponentContext;
+
+/**
+ * Overrides some behavior of {@link ResourceResolverFactoryActivator} to allow
+ * usage in mocking.
+ */
+class MockResourceResolverFactoryActivator extends ResourceResolverFactoryActivator {
+
+    // make public
+    @Override
+    public void activate(final ComponentContext componentContext) {
+        super.activate(componentContext);
+    }
+
+    // make public
+    @Override
+    public void bindResourceProviderFactory(final ResourceProviderFactory provider, final Map<String, Object> props) {
+        super.bindResourceProviderFactory(provider, props);
+    }
+
+    // make public
+    @Override
+    public void bindResourceProvider(final ResourceProvider provider, final Map<String, Object> props) {
+        super.bindResourceProvider(provider, props);
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/MockSling.java b/src/main/java/org/apache/sling/testing/mock/sling/MockSling.java
new file mode 100644
index 0000000..208a8d1
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/MockSling.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.sling;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.adapter.SlingAdaptable;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
+import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
+import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletResponse;
+import org.apache.sling.testing.mock.sling.spi.ResourceResolverTypeAdapter;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Factory for mock Sling objects.
+ */
+public final class MockSling {
+
+    /**
+     * Default resource resolver type is {@link ResourceResolverType#RESOURCERESOLVER_MOCK}.
+     */
+    public static final ResourceResolverType DEFAULT_RESOURCERESOLVER_TYPE = ResourceResolverType.RESOURCERESOLVER_MOCK;
+
+    private static final ThreadsafeMockAdapterManagerWrapper ADAPTER_MANAGER = new ThreadsafeMockAdapterManagerWrapper();
+    static {
+        // register mocked adapter manager
+        SlingAdaptable.setAdapterManager(ADAPTER_MANAGER);
+    }
+
+    private MockSling() {
+        // static methods only
+    }
+
+    /**
+     * Creates new sling resource resolver factory instance.
+     * @param type Type of underlying repository.
+     * @return Resource resolver factory instance
+     */
+    public static ResourceResolverFactory newResourceResolverFactory(final ResourceResolverType type) {
+        ResourceResolverTypeAdapter adapter = getResourceResolverTypeAdapter(type);
+        ResourceResolverFactory factory = adapter.newResourceResolverFactory();
+        if (factory == null) {
+            SlingRepository repository = adapter.newSlingRepository();
+            if (repository == null) {
+                throw new RuntimeException("Adapter neither provides resource resolver factory nor sling repository.");
+            }
+            factory = new MockJcrResourceResolverFactory(repository);
+        }
+        return factory;
+    }
+
+    private static ResourceResolverTypeAdapter getResourceResolverTypeAdapter(final ResourceResolverType type) {
+        try {
+            Class clazz = Class.forName(type.getResourceResolverTypeAdapterClass());
+            return (ResourceResolverTypeAdapter) clazz.newInstance();
+        } catch (ClassNotFoundException ex) {
+            throw new RuntimeException("Unable to instantiate resourcer resolver: "
+                    + type.getResourceResolverTypeAdapterClass()
+                    + (type.getArtifactCoordinates() != null ? "Make sure this maven dependency is included: "
+                            + type.getArtifactCoordinates() : ""), ex);
+        } catch (InstantiationException ex) {
+            throw new RuntimeException("Unable to instantiate resourcer resolver: "
+                    + type.getResourceResolverTypeAdapterClass()
+                    + (type.getArtifactCoordinates() != null ? "Make sure this maven dependency is included: "
+                            + type.getArtifactCoordinates() : ""), ex);
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException("Unable to instantiate resourcer resolver: "
+                    + type.getResourceResolverTypeAdapterClass()
+                    + (type.getArtifactCoordinates() != null ? "Make sure this maven dependency is included: "
+                            + type.getArtifactCoordinates() : ""), ex);
+        }
+    }
+
+    /**
+     * Creates new sling resource resolver factory instance using
+     * {@link #DEFAULT_RESOURCERESOLVER_TYPE}.
+     * @return Resource resolver factory instance
+     */
+    public static ResourceResolverFactory newResourceResolverFactory() {
+        return newResourceResolverFactory(DEFAULT_RESOURCERESOLVER_TYPE);
+    }
+
+    /**
+     * Creates new sling resource resolver instance.
+     * @param type Type of underlying repository.
+     * @return Resource resolver instance
+     */
+    public static ResourceResolver newResourceResolver(final ResourceResolverType type) {
+        ResourceResolverFactory factory = newResourceResolverFactory(type);
+        try {
+            return factory.getResourceResolver(null);
+        } catch (LoginException ex) {
+            throw new RuntimeException("Mock resource resolver factory implementation seems to require login.", ex);
+        }
+    }
+
+    /**
+     * Creates new sling resource resolver instance using
+     * {@link #DEFAULT_RESOURCERESOLVER_TYPE}.
+     * @return Resource resolver instance
+     */
+    public static ResourceResolver newResourceResolver() {
+        return newResourceResolver(DEFAULT_RESOURCERESOLVER_TYPE);
+    }
+
+    /**
+     * Creates a new sling script helper instance.
+     * @param request Request
+     * @param response Response
+     * @param bundleContext Bundle context
+     * @return Sling script helper instance
+     */
+    public static SlingScriptHelper newSlingScriptHelper(final SlingHttpServletRequest request,
+            final SlingHttpServletResponse response, final BundleContext bundleContext) {
+        return new MockSlingScriptHelper(request, response, bundleContext);
+    }
+
+    /**
+     * Creates a new sling script helper instance using
+     * {@link #DEFAULT_RESOURCERESOLVER_TYPE} for the resource resolver.
+     * @return Sling script helper instance
+     */
+    public static SlingScriptHelper newSlingScriptHelper() {
+        SlingHttpServletRequest request = new MockSlingHttpServletRequest(newResourceResolver());
+        SlingHttpServletResponse response = new MockSlingHttpServletResponse();
+        BundleContext bundleContext = MockOsgi.newBundleContext();
+        return newSlingScriptHelper(request, response, bundleContext);
+    }
+
+    /**
+     * Set bundle context for adapter manager. From this bundle context the
+     * adapter factories are detected.
+     * @param bundleContext OSGi bundle context
+     */
+    public static void setAdapterManagerBundleContext(final BundleContext bundleContext) {
+        ADAPTER_MANAGER.setBundleContext(bundleContext);
+    }
+
+    /**
+     * Clear adapter registrations..
+     */
+    public static void clearAdapterManagerBundleContext() {
+        ADAPTER_MANAGER.clearBundleContext();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/MockSlingRepository.java b/src/main/java/org/apache/sling/testing/mock/sling/MockSlingRepository.java
new file mode 100644
index 0000000..1e33847
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/MockSlingRepository.java
@@ -0,0 +1,112 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling;
+
+import javax.jcr.Credentials;
+import javax.jcr.LoginException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.testing.mock.jcr.MockJcr;
+
+/**
+ * Mock {@link SlingRepository} implementation.
+ */
+class MockSlingRepository implements SlingRepository {
+
+    private final Repository delegate;
+
+    public MockSlingRepository(final Repository delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public Session loginAdministrative(final String workspace) throws RepositoryException {
+        return login();
+    }
+
+    @Override
+    public Session loginService(final String subServiceName, final String workspace) throws LoginException,
+            RepositoryException {
+        return login();
+    }
+
+    @Override
+    public String getDefaultWorkspace() {
+        return MockJcr.DEFAULT_WORKSPACE;
+    }
+
+    // delegated methods
+    @Override
+    public String[] getDescriptorKeys() {
+        return this.delegate.getDescriptorKeys();
+    }
+
+    @Override
+    public boolean isStandardDescriptor(final String key) {
+        return this.delegate.isStandardDescriptor(key);
+    }
+
+    @Override
+    public boolean isSingleValueDescriptor(final String key) {
+        return this.delegate.isSingleValueDescriptor(key);
+    }
+
+    @Override
+    public Value getDescriptorValue(final String key) {
+        return this.delegate.getDescriptorValue(key);
+    }
+
+    @Override
+    public Value[] getDescriptorValues(final String key) {
+        return this.delegate.getDescriptorValues(key);
+    }
+
+    @Override
+    public String getDescriptor(final String key) {
+        return this.delegate.getDescriptor(key);
+    }
+
+    @Override
+    public Session login(final Credentials credentials, final String workspaceName) throws LoginException,
+            NoSuchWorkspaceException, RepositoryException {
+        return this.delegate.login(credentials, workspaceName);
+    }
+
+    @Override
+    public Session login(final Credentials credentials) throws LoginException, RepositoryException {
+        return this.delegate.login(credentials);
+    }
+
+    @Override
+    public Session login(final String workspaceName) throws LoginException, NoSuchWorkspaceException,
+            RepositoryException {
+        return this.delegate.login(workspaceName);
+    }
+
+    @Override
+    public Session login() throws LoginException, RepositoryException {
+        return this.delegate.login();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/MockSlingScriptHelper.java b/src/main/java/org/apache/sling/testing/mock/sling/MockSlingScriptHelper.java
new file mode 100644
index 0000000..5882d9d
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/MockSlingScriptHelper.java
@@ -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 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 org.apache.sling.testing.mock.sling;
+
+import java.lang.reflect.Array;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.request.RequestDispatcherOptions;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.scripting.InvalidServiceFilterSyntaxException;
+import org.apache.sling.api.scripting.SlingScript;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Mock {@link SlingScriptHelper} implementation.
+ */
+class MockSlingScriptHelper implements SlingScriptHelper {
+
+    private final SlingHttpServletRequest request;
+    private final SlingHttpServletResponse response;
+    private final BundleContext bundleContext;
+
+    public MockSlingScriptHelper(final SlingHttpServletRequest request, final SlingHttpServletResponse response,
+            final BundleContext bundleContext) {
+        this.request = request;
+        this.response = response;
+        this.bundleContext = bundleContext;
+    }
+
+    @Override
+    public SlingHttpServletRequest getRequest() {
+        return this.request;
+    }
+
+    @Override
+    public SlingHttpServletResponse getResponse() {
+        return this.response;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <ServiceType> ServiceType getService(final Class<ServiceType> serviceType) {
+        ServiceReference serviceReference = this.bundleContext.getServiceReference(serviceType.getName());
+        if (serviceReference != null) {
+            return (ServiceType) this.bundleContext.getService(serviceReference);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <ServiceType> ServiceType[] getServices(final Class<ServiceType> serviceType, final String filter) {
+        try {
+            ServiceReference[] serviceReferences = this.bundleContext.getServiceReferences(serviceType.getName(),
+                    filter);
+            if (serviceReferences != null) {
+                ServiceType[] services = (ServiceType[]) Array.newInstance(serviceType, serviceReferences.length);
+                for (int i = 0; i < serviceReferences.length; i++) {
+                    services[i] = (ServiceType) this.bundleContext.getService(serviceReferences[i]);
+                }
+                return services;
+            } else {
+                return (ServiceType[]) ArrayUtils.EMPTY_OBJECT_ARRAY;
+            }
+        } catch (InvalidSyntaxException ex) {
+            throw new InvalidServiceFilterSyntaxException(filter, ex.getMessage(), ex);
+        }
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public void dispose() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void forward(final String path, final RequestDispatcherOptions requestDispatcherOptions) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void forward(final String path, final String requestDispatcherOptions) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void forward(final String path) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void forward(final Resource resource) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void forward(final Resource resource, final String requestDispatcherOptions) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void forward(final Resource resource, final RequestDispatcherOptions requestDispatcherOptions) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SlingScript getScript() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void include(final String path, final RequestDispatcherOptions requestDispatcherOptions) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void include(final String path, final String requestDispatcherOptions) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void include(final String path) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void include(final Resource resource) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void include(final Resource resource, final String requestDispatcherOptions) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void include(final Resource resource, final RequestDispatcherOptions requestDispatcherOptions) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/RRMockMockResourceResolverAdapter.java b/src/main/java/org/apache/sling/testing/mock/sling/RRMockMockResourceResolverAdapter.java
new file mode 100644
index 0000000..47c4a64
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/RRMockMockResourceResolverAdapter.java
@@ -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.
+ */
+package org.apache.sling.testing.mock.sling;
+
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.testing.mock.sling.spi.ResourceResolverTypeAdapter;
+import org.apache.sling.testing.resourceresolver.MockResourceResolverFactory;
+import org.apache.sling.testing.resourceresolver.MockResourceResolverFactoryOptions;
+
+/**
+ * Resource resolver type adapter for Sling Resource Resolver Mock implementation.
+ */
+class RRMockMockResourceResolverAdapter implements ResourceResolverTypeAdapter {
+
+    private final MockResourceResolverFactoryOptions options;
+
+    /**
+     * Constructor
+     */
+    public RRMockMockResourceResolverAdapter() {
+        options = new MockResourceResolverFactoryOptions();
+        options.setMangleNamespacePrefixes(true);
+    }
+
+    @Override
+    public ResourceResolverFactory newResourceResolverFactory() {
+        return new MockResourceResolverFactory(options);
+    }
+
+    @Override
+    public SlingRepository newSlingRepository() {
+        return null;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/ResourceResolverType.java b/src/main/java/org/apache/sling/testing/mock/sling/ResourceResolverType.java
new file mode 100644
index 0000000..915c124
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/ResourceResolverType.java
@@ -0,0 +1,86 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling;
+
+/**
+ * The resource resolver mock implementation supports different underlying
+ * repository implementations.
+ */
+public enum ResourceResolverType {
+
+    /**
+     * Uses Sling "resourceresolver-mock" implementation, no underlying JCR
+     * repository.
+     * <ul>
+     * <li>Simulates an In-Memory resource tree, does not provide adaptions to
+     * JCR.</li>
+     * <li>You can use it to make sure the code you want to test does not
+     * contain references to JCR API.</li>
+     * <li>Behaves slightly different from JCR resource mapping e.g. handling
+     * binary and date values.</li>
+     * <li>This resource resolver type is very fast.</li>
+     * </ul>
+     */
+    RESOURCERESOLVER_MOCK(RRMockMockResourceResolverAdapter.class.getName(), null),
+
+    /**
+     * Uses a simple JCR "in-memory" mock as underlying repository.
+     * <ul>
+     * <li>Uses the real Sling Resource Resolver and JCR Resource mapping
+     * implementation.</li>
+     * <li>The mock JCR implementation from Apache Sling is used.</li>
+     * <li>It supports the most important, but not all JCR features. Extended
+     * features like Versioning, Eventing, Search, Transaction handling etc. are
+     * not supported.</li>
+     * <li>This resource resolver type is quite fast.</li>
+     * </ul>
+     */
+    JCR_MOCK(JcrMockResourceResolverAdapter.class.getName(), null),
+
+    /**
+     * Uses a real JCR Jackrabbit repository.
+     * <ul>
+     * <li>Uses the real Sling Resource Resolver and JCR Resource mapping
+     * implementation.</li>
+     * <li>The JCR repository is started on first access, this may take some
+     * seconds.</li>
+     * <li>Beware: The repository is not cleared for each unit test, so make
+     * sure us use a unique node path for each unit test.</li>
+     * </ul>
+     */
+    JCR_JACKRABBIT("org.apache.sling.testing.mock.sling.jackrabbit.JackrabbitMockResourceResolverAdapter",
+            "org.apache.sling:org.apache.sling.testing.sling-mock-jackrabbit");
+
+    private final String resourceResolverTypeAdapterClass;
+    private final String artifactCoordinates;
+
+    private ResourceResolverType(final String resourceResolverTypeAdapterClass, final String artifactCoordinates) {
+        this.resourceResolverTypeAdapterClass = resourceResolverTypeAdapterClass;
+        this.artifactCoordinates = artifactCoordinates;
+    }
+
+    String getResourceResolverTypeAdapterClass() {
+        return this.resourceResolverTypeAdapterClass;
+    }
+
+    String getArtifactCoordinates() {
+        return this.artifactCoordinates;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/ThreadsafeMockAdapterManagerWrapper.java b/src/main/java/org/apache/sling/testing/mock/sling/ThreadsafeMockAdapterManagerWrapper.java
new file mode 100644
index 0000000..2e1f834
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/ThreadsafeMockAdapterManagerWrapper.java
@@ -0,0 +1,61 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling;
+
+import org.apache.sling.api.adapter.AdapterManager;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Wrapper for {@link MockAdapterManager} which makes sure multiple unit tests
+ * running in parallel do not get in conflict with each other. Instead, a
+ * different {@link MockAdapterManager} is used per thread.
+ */
+class ThreadsafeMockAdapterManagerWrapper implements AdapterManager {
+
+    private static final ThreadLocal<MockAdapterManager> THREAD_LOCAL = new ThreadLocal<MockAdapterManager>() {
+        @Override
+        protected MockAdapterManager initialValue() {
+            return new MockAdapterManager();
+        }
+    };
+
+    @Override
+    public <AdapterType> AdapterType getAdapter(final Object adaptable, final Class<AdapterType> type) {
+        MockAdapterManager adapterManager = THREAD_LOCAL.get();
+        return adapterManager.getAdapter(adaptable, type);
+    }
+
+    /**
+     * Sets bundle context.
+     * @param bundleContext Bundle context
+     */
+    public void setBundleContext(final BundleContext bundleContext) {
+        MockAdapterManager adapterManager = THREAD_LOCAL.get();
+        adapterManager.setBundleContext(bundleContext);
+    }
+
+    /**
+     * Removes bundle context reference.
+     */
+    public void clearBundleContext() {
+        MockAdapterManager adapterManager = THREAD_LOCAL.get();
+        adapterManager.clearBundleContext();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/builder/ContentBuilder.java b/src/main/java/org/apache/sling/testing/mock/sling/builder/ContentBuilder.java
new file mode 100644
index 0000000..19b3979
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/builder/ContentBuilder.java
@@ -0,0 +1,108 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.builder;
+
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Helper class for building test content in the resource hierarchy with as less
+ * boilerplate code as possible.
+ */
+public class ContentBuilder {
+
+    static final String DUMMY_TEMPLATE = "/apps/sample/templates/template1";
+
+    protected final ResourceResolver resourceResolver;
+
+    /**
+     * @param resourceResolver Resource resolver
+     */
+    public ContentBuilder(ResourceResolver resourceResolver) {
+        this.resourceResolver = resourceResolver;
+    }
+
+    /**
+     * Create resource. If parent resource(s) do not exist they are created
+     * automatically using <code>nt:unstructured</code> nodes.
+     * @param path Page path
+     * @return Resource object
+     */
+    public final Resource resource(String path) {
+        return resource(path, ValueMap.EMPTY);
+    }
+
+    /**
+     * Create resource. If parent resource(s) do not exist they are created
+     * automatically using <code>nt:unstructured</code> nodes.
+     * @param path Page path
+     * @param properties Properties for resource.
+     * @return Resource object
+     */
+    public final Resource resource(String path, Map<String, Object> properties) {
+        String parentPath = ResourceUtil.getParent(path);
+        Resource parentResource = ensureResourceExists(parentPath);
+        String name = ResourceUtil.getName(path);
+        try {
+            return resourceResolver.create(parentResource, name, properties);
+        } catch (PersistenceException ex) {
+            throw new RuntimeException("Unable to create page at " + path, ex);
+        }
+    }
+
+    /**
+     * Ensure that a resource exists at the given path. If not, it is created
+     * using <code>nt:unstructured</code> node type.
+     * @param path Resource path
+     * @return Resource at path (existing or newly created)
+     */
+    protected final Resource ensureResourceExists(String path) {
+        if (StringUtils.isEmpty(path) || StringUtils.equals(path, "/")) {
+            return resourceResolver.getResource("/");
+        }
+        Resource resource = resourceResolver.getResource(path);
+        if (resource != null) {
+            return resource;
+        }
+        String parentPath = ResourceUtil.getParent(path);
+        String name = ResourceUtil.getName(path);
+        Resource parentResource = ensureResourceExists(parentPath);
+        try {
+            resource = resourceResolver.create(
+                    parentResource,
+                    name,
+                    ImmutableMap.<String, Object> builder()
+                            .put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED).build());
+            resourceResolver.commit();
+            return resource;
+        } catch (PersistenceException ex) {
+            throw new RuntimeException("Unable to create resource at " + path, ex);
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/builder/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/builder/package-info.java
new file mode 100644
index 0000000..41f7c62
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/builder/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * Content builder for creating test content.
+ */
+package org.apache.sling.testing.mock.sling.builder;
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java b/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java
new file mode 100644
index 0000000..a8596ae
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java
@@ -0,0 +1,77 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.context;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+
+/**
+ * Create resolve resolver instance and initialize it depending on it's type.
+ */
+final class ContextResourceResolverFactory {
+
+    private ContextResourceResolverFactory() {
+        // static methods only
+    }
+
+    public static ResourceResolver initializeResourceResolver(final ResourceResolverType resourceResolverType) {
+        try {
+            ResourceResolver resourceResolver = MockSling.newResourceResolver(resourceResolverType);
+
+            switch (resourceResolverType) {
+            case JCR_MOCK:
+                initializeJcrMock(resourceResolver);
+                break;
+            case JCR_JACKRABBIT:
+                initializeJcrJackrabbit(resourceResolver);
+                break;
+            case RESOURCERESOLVER_MOCK:
+                initializeResourceResolverMock(resourceResolver);
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid resource resolver type: " + resourceResolverType);
+            }
+
+            return resourceResolver;
+        } catch (Throwable ex) {
+            throw new RuntimeException("Unable to initialize " + resourceResolverType + " resource resolver.", ex);
+        }
+    }
+
+    private static void initializeJcrMock(final ResourceResolver resourceResolver) throws RepositoryException {
+        // register default namespaces
+        NamespaceRegistry namespaceRegistry = resourceResolver.adaptTo(Session.class).getWorkspace()
+                .getNamespaceRegistry();
+        namespaceRegistry.registerNamespace("sling", "http://sling.apache.org/jcr/sling/1.0");
+    }
+
+    private static void initializeJcrJackrabbit(final ResourceResolver resourceResolver) {
+        // TODO: register sling node types
+    }
+
+    private static void initializeResourceResolverMock(final ResourceResolver resourceResolver) {
+        // nothing to do
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java b/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
new file mode 100644
index 0000000..d72434d
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
@@ -0,0 +1,401 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.context;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.sling.api.adapter.AdapterFactory;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.commons.mime.MimeTypeService;
+import org.apache.sling.models.impl.FirstImplementationPicker;
+import org.apache.sling.models.impl.injectors.BindingsInjector;
+import org.apache.sling.models.impl.injectors.ChildResourceInjector;
+import org.apache.sling.models.impl.injectors.OSGiServiceInjector;
+import org.apache.sling.models.impl.injectors.RequestAttributeInjector;
+import org.apache.sling.models.impl.injectors.ResourcePathInjector;
+import org.apache.sling.models.impl.injectors.ResourceResolverInjector;
+import org.apache.sling.models.impl.injectors.SelfInjector;
+import org.apache.sling.models.impl.injectors.SlingObjectInjector;
+import org.apache.sling.models.impl.injectors.ValueMapInjector;
+import org.apache.sling.models.spi.ImplementationPicker;
+import org.apache.sling.models.spi.Injector;
+import org.apache.sling.settings.SlingSettingsService;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.builder.ContentBuilder;
+import org.apache.sling.testing.mock.sling.loader.ContentLoader;
+import org.apache.sling.testing.mock.sling.services.MockMimeTypeService;
+import org.apache.sling.testing.mock.sling.services.MockModelAdapterFactory;
+import org.apache.sling.testing.mock.sling.services.MockSlingSettingService;
+import org.apache.sling.testing.mock.sling.servlet.MockRequestPathInfo;
+import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
+import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletResponse;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Defines Sling context objects with lazy initialization. Should not be used
+ * directly but via the {@link org.apache.sling.testing.mock.sling.junit.SlingContext} JUnit
+ * rule.
+ */
+public class SlingContextImpl {
+
+    // default to publish instance run mode
+    static final Set<String> DEFAULT_RUN_MODES = ImmutableSet.<String> builder().add("publish").build();
+
+    protected MockModelAdapterFactory modelAdapterFactory;
+    protected ResourceResolverType resourceResolverType;
+    protected ComponentContext componentContext;
+    protected ResourceResolver resourceResolver;
+    protected MockSlingHttpServletRequest request;
+    protected MockSlingHttpServletResponse response;
+    protected SlingScriptHelper slingScriptHelper;
+    protected ContentLoader contentLoader;
+    protected ContentBuilder contentBuilder;
+
+    /**
+     * @param resourceResolverType Resource resolver type
+     */
+    protected void setResourceResolverType(final ResourceResolverType resourceResolverType) {
+        this.resourceResolverType = resourceResolverType;
+    }
+
+    /**
+     * Setup actions before test method execution
+     */
+    protected void setUp() {
+        MockSling.setAdapterManagerBundleContext(bundleContext());
+        registerDefaultServices();
+    }
+
+    /**
+     * Default services that should be available for every unit test
+     */
+    protected void registerDefaultServices() {
+
+        // adapter factories
+        modelAdapterFactory = new MockModelAdapterFactory(componentContext());
+        registerService(AdapterFactory.class, modelAdapterFactory);
+
+        // sling models injectors
+        registerService(Injector.class, new BindingsInjector());
+        registerService(Injector.class, new ChildResourceInjector());
+        OSGiServiceInjector osgiServiceInjector = new OSGiServiceInjector();
+        osgiServiceInjector.activate(componentContext());
+        registerService(Injector.class, osgiServiceInjector);
+        registerService(Injector.class, new RequestAttributeInjector());
+        registerService(Injector.class, new ResourcePathInjector());
+        registerService(Injector.class, new ResourceResolverInjector());
+        registerService(Injector.class, new SelfInjector());
+        registerService(Injector.class, new SlingObjectInjector());
+        registerService(Injector.class, new ValueMapInjector());
+
+        // sling models implementation pickers
+        registerService(ImplementationPicker.class, new FirstImplementationPicker());
+
+        // other services
+        registerService(SlingSettingsService.class, new MockSlingSettingService(DEFAULT_RUN_MODES));
+        registerService(MimeTypeService.class, new MockMimeTypeService());
+    }
+
+    /**
+     * Teardown actions after test method execution
+     */
+    protected void tearDown() {
+
+        if (this.resourceResolver != null) {
+            // revert potential unsaved changes in resource resolver/JCR session
+            this.resourceResolver.revert();
+            Session session = this.resourceResolver.adaptTo(Session.class);
+            if (session != null) {
+                try {
+                    session.refresh(false);
+                } catch (RepositoryException ex) {
+                    // ignore
+                }
+            }
+        }
+
+        this.modelAdapterFactory = null;
+        this.componentContext = null;
+        this.resourceResolver = null;
+        this.request = null;
+        this.response = null;
+        this.slingScriptHelper = null;
+        this.contentLoader = null;
+        this.contentBuilder = null;
+
+        MockSling.clearAdapterManagerBundleContext();
+    }
+
+    /**
+     * @return Resource resolver type
+     */
+    public final ResourceResolverType resourceResolverType() {
+        return this.resourceResolverType;
+    }
+
+    /**
+     * @return OSGi component context
+     */
+    public final ComponentContext componentContext() {
+        if (this.componentContext == null) {
+            this.componentContext = MockOsgi.newComponentContext();
+        }
+        return this.componentContext;
+    }
+
+    /**
+     * @return OSGi Bundle context
+     */
+    public final BundleContext bundleContext() {
+        return componentContext().getBundleContext();
+    }
+
+    /**
+     * @return Resource resolver
+     */
+    public final ResourceResolver resourceResolver() {
+        if (this.resourceResolver == null) {
+            this.resourceResolver = createMockResourceResolver();
+        }
+        return this.resourceResolver;
+    }
+    
+    protected ResourceResolver createMockResourceResolver() {
+        return ContextResourceResolverFactory.initializeResourceResolver(resourceResolverType());
+    }
+
+    /**
+     * @return Sling request
+     */
+    public final MockSlingHttpServletRequest request() {
+        if (this.request == null) {
+            this.request = new MockSlingHttpServletRequest(this.resourceResolver());
+
+            // initialize sling bindings
+            SlingBindings bindings = new SlingBindings();
+            bindings.put(SlingBindings.REQUEST, this.request);
+            bindings.put(SlingBindings.RESPONSE, response());
+            bindings.put(SlingBindings.SLING, slingScriptHelper());
+            this.request.setAttribute(SlingBindings.class.getName(), bindings);
+        }
+        return this.request;
+    }
+
+    /**
+     * @return Request path info
+     */
+    public final MockRequestPathInfo requestPathInfo() {
+        return (MockRequestPathInfo) request().getRequestPathInfo();
+    }
+
+    /**
+     * @return Sling response
+     */
+    public final MockSlingHttpServletResponse response() {
+        if (this.response == null) {
+            this.response = new MockSlingHttpServletResponse();
+        }
+        return this.response;
+    }
+
+    /**
+     * @return Sling script helper
+     */
+    public final SlingScriptHelper slingScriptHelper() {
+        if (this.slingScriptHelper == null) {
+            this.slingScriptHelper = MockSling.newSlingScriptHelper(this.request(), this.response(),
+                    this.bundleContext());
+        }
+        return this.slingScriptHelper;
+    }
+
+    /**
+     * @return Content loader
+     */
+    public ContentLoader load() {
+        if (this.contentLoader == null) {
+            this.contentLoader = new ContentLoader(resourceResolver(), bundleContext());
+        }
+        return this.contentLoader;
+    }
+
+    /**
+     * @return Content builder for building test content
+     */
+    public ContentBuilder create() {
+        if (this.contentBuilder == null) {
+            this.contentBuilder = new ContentBuilder(resourceResolver());
+        }
+        return this.contentBuilder;
+    }
+
+    /**
+     * Registers a service in the mocked OSGi environment.
+     * @param service Service instance
+     * @return Registered service instance
+     */
+    public final <T> T registerService(final T service) {
+        return registerService(null, service, null);
+    }
+
+    /**
+     * Registers a service in the mocked OSGi environment.
+     * @param serviceClass Service class
+     * @param service Service instance
+     * @return Registered service instance
+     */
+    public final <T> T registerService(final Class<T> serviceClass, final T service) {
+        return registerService(serviceClass, service, null);
+    }
+
+    /**
+     * Registers a service in the mocked OSGi environment.
+     * @param serviceClass Service class
+     * @param service Service instance
+     * @param properties Service properties (optional)
+     * @return Registered service instance
+     */
+    public final <T> T registerService(final Class<T> serviceClass, final T service, final Map<String, Object> properties) {
+        Dictionary<String, Object> serviceProperties = null;
+        if (properties != null) {
+            serviceProperties = new Hashtable<String, Object>(properties);
+        }
+        bundleContext().registerService(serviceClass != null ? serviceClass.getName() : null, service,
+                serviceProperties);
+        return service;
+    }
+
+    /**
+     * Injects dependencies, activates and registers a service in the mocked
+     * OSGi environment.
+     * @param service Service instance
+     * @return Registered service instance
+     */
+    public final <T> T registerInjectActivateService(final T service) {
+        return registerInjectActivateService(service, ImmutableMap.<String, Object> of());
+    }
+
+    /**
+     * Injects dependencies, activates and registers a service in the mocked
+     * OSGi environment.
+     * @param service Service instance
+     * @param properties Service properties (optional)
+     * @return Registered service instance
+     */
+    public final <T> T registerInjectActivateService(final T service, final Map<String, Object> properties) {
+        MockOsgi.injectServices(service, bundleContext());
+        MockOsgi.activate(service, bundleContext(), properties);
+        registerService(null, service, null);
+        return service;
+    }
+
+    /**
+     * Lookup a single service
+     * @param serviceType The type (interface) of the service.
+     * @return The service instance, or null if the service is not available.
+     */
+    public final <ServiceType> ServiceType getService(final Class<ServiceType> serviceType) {
+        return slingScriptHelper().getService(serviceType);
+    }
+
+    /**
+     * Lookup one or several services
+     * @param serviceType The type (interface) of the service.
+     * @param filter An optional filter (LDAP-like, see OSGi spec)
+     * @return The services object or null.
+     * @throws InvalidServiceFilterSyntaxException If the <code>filter</code>
+     *             string is not a valid OSGi service filter string.
+     */
+    public final <ServiceType> ServiceType[] getServices(final Class<ServiceType> serviceType, final String filter) {
+        return slingScriptHelper().getServices(serviceType, filter);
+    }
+
+    /**
+     * @return Current resource
+     */
+    public final Resource currentResource() {
+        return request().getResource();
+    }
+
+    /**
+     * Set current resource in request.
+     * @param resourcePath Resource path
+     * @return Current resource
+     */
+    public final Resource currentResource(String resourcePath) {
+        if (resourcePath != null) {
+            Resource resource = resourceResolver().getResource(resourcePath);
+            if (resource == null) {
+                throw new IllegalArgumentException("Resource does not exist: " + resourcePath);
+            }
+            return currentResource(resource);
+        } else {
+            return currentResource((Resource) null);
+        }
+    }
+
+    /**
+     * Set current resource in request.
+     * @param resource Resource
+     * @return Current resource
+     */
+    public final Resource currentResource(Resource resource) {
+        request().setResource(resource);
+        return resource;
+    }
+
+    /**
+     * Scan classpaths for given package name (and sub packages) to scan for and
+     * register all classes with @Model annotation.
+     * @param packageName Java package name
+     */
+    public final void addModelsForPackage(String packageName) {
+        this.modelAdapterFactory.addModelsForPackage(packageName);
+    }
+
+    /**
+     * Set current run mode(s).
+     * @param runModes Run mode(s).
+     */
+    public final void runMode(String... runModes) {
+        Set<String> newRunModes = ImmutableSet.<String> builder().add(runModes).build();
+        ServiceReference ref = bundleContext().getServiceReference(SlingSettingsService.class.getName());
+        if (ref != null) {
+            MockSlingSettingService slingSettings = (MockSlingSettingService) bundleContext().getService(ref);
+            slingSettings.setRunModes(newRunModes);
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/context/package-info.java
new file mode 100644
index 0000000..e229f1e
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/**
+ * Sling context implementation for unit tests.
+ */
+package org.apache.sling.testing.mock.sling.context;
+
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContext.java b/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContext.java
new file mode 100644
index 0000000..51ea608
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContext.java
@@ -0,0 +1,207 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.junit;
+
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.context.SlingContextImpl;
+import org.junit.rules.ExternalResource;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * JUnit rule for setting up and tearing down Sling context objects for unit
+ * tests.
+ */
+public final class SlingContext extends SlingContextImpl implements TestRule {
+
+    private final SlingContextCallback setUpCallback;
+    private final SlingContextCallback tearDownCallback;
+    private final ResourceResolverType resourceResolverType;
+    private final TestRule delegate;
+
+    /**
+     * Initialize Sling context.
+     * <p>
+     * If context is initialized with:
+     * </p>
+     * <ul>
+     * <li>No resource resolver type - default is used
+     * {@link MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.</li>
+     * <li>One resource resolver type - exactly this is used.</li>
+     * <li>More than one: all unit test methods are executed for all resource
+     * resolver types using {@link ListGenerator}.</li>
+     * </ul>
+     */
+    public SlingContext() {
+        this(null, null, null);
+    }
+
+    /**
+     * Initialize Sling context.
+     * <p>
+     * If context is initialized with:
+     * </p>
+     * <ul>
+     * <li>No resource resolver type - default is used
+     * {@link MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.</li>
+     * <li>One resource resolver type - exactly this is used.</li>
+     * <li>More than one: all unit test methods are executed for all resource
+     * resolver types using {@link ListGenerator}.</li>
+     * </ul>
+     * @param resourceResolverType Resource resolver type.
+     */
+    public SlingContext(final ResourceResolverType resourceResolverType) {
+        this(null, null, resourceResolverType);
+    }
+
+    /**
+     * Initialize Sling context.
+     * <p>
+     * If context is initialized with:
+     * </p>
+     * <ul>
+     * <li>No resource resolver type - default is used
+     * {@link MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.</li>
+     * <li>One resource resolver type - exactly this is used.</li>
+     * <li>More than one: all unit test methods are executed for all resource
+     * resolver types using {@link ListGenerator}.</li>
+     * </ul>
+     * @param setUpCallback Allows the application to register an own callback
+     *            function that is called after the built-in setup rules are
+     *            executed.
+     */
+    public SlingContext(final SlingContextCallback setUpCallback) {
+        this(setUpCallback, null, null);
+    }
+
+    /**
+     * Initialize Sling context.
+     * <p>
+     * If context is initialized with:
+     * </p>
+     * <ul>
+     * <li>No resource resolver type - default is used
+     * {@link MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.</li>
+     * <li>One resource resolver type - exactly this is used.</li>
+     * <li>More than one: all unit test methods are executed for all resource
+     * resolver types using {@link ListGenerator}.</li>
+     * </ul>
+     * @param setUpCallback Allows the application to register an own callback
+     *            function that is called after the built-in setup rules are
+     *            executed.
+     * @param resourceResolverType Resource resolver type.
+     */
+    public SlingContext(final SlingContextCallback setUpCallback, final ResourceResolverType resourceResolverType) {
+        this(setUpCallback, null, resourceResolverType);
+    }
+
+    /**
+     * Initialize Sling context.
+     * <p>
+     * If context is initialized with:
+     * </p>
+     * <ul>
+     * <li>No resource resolver type - default is used
+     * {@link MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.</li>
+     * <li>One resource resolver type - exactly this is used.</li>
+     * <li>More than one: all unit test methods are executed for all resource
+     * resolver types using {@link ListGenerator}.</li>
+     * </ul>
+     * @param setUpCallback Allows the application to register an own callback
+     *            function that is called after the built-in setup rules are
+     *            executed.
+     * @param tearDownCallback Allows the application to register an own
+     *            callback function that is called before the built-in teardown
+     *            rules are executed.
+     */
+    public SlingContext(final SlingContextCallback setUpCallback, final SlingContextCallback tearDownCallback) {
+        this(setUpCallback, tearDownCallback, null);
+    }
+    
+    /**
+     * Initialize Sling context.
+     * <p>
+     * If context is initialized with:
+     * </p>
+     * <ul>
+     * <li>No resource resolver type - default is used
+     * {@link MockSling#DEFAULT_RESOURCERESOLVER_TYPE}.</li>
+     * <li>One resource resolver type - exactly this is used.</li>
+     * <li>More than one: all unit test methods are executed for all resource
+     * resolver types using {@link ListGenerator}.</li>
+     * </ul>
+     * @param setUpCallback Allows the application to register an own callback
+     *            function that is called after the built-in setup rules are
+     *            executed.
+     * @param tearDownCallback Allows the application to register an own
+     *            callback function that is called before the built-in teardown
+     *            rules are executed.
+     * @param resourceResolverType Resource resolver type.
+     */
+    public SlingContext(final SlingContextCallback setUpCallback, final SlingContextCallback tearDownCallback,
+            final ResourceResolverType resourceResolverType) {
+
+        this.setUpCallback = setUpCallback;
+        this.tearDownCallback = tearDownCallback;
+        this.resourceResolverType = resourceResolverType;
+
+        // user default rule that directly executes each test method once
+        setResourceResolverType(this.resourceResolverType);
+        this.delegate = new ExternalResource() {
+            @Override
+            protected void before() {
+                SlingContext.this.setUp();
+                SlingContext.this.executeSetUpCallback();
+            }
+
+            @Override
+            protected void after() {
+                SlingContext.this.executeTearDownCallback();
+                SlingContext.this.tearDown();
+            }
+        };
+    }
+
+    @Override
+    public Statement apply(final Statement base, final Description description) {
+        return this.delegate.apply(base, description);
+    }
+
+    private void executeSetUpCallback() {
+        if (this.setUpCallback != null) {
+            try {
+                this.setUpCallback.execute(this);
+            } catch (Throwable ex) {
+                throw new RuntimeException("Executing setup callback failed.", ex);
+            }
+        }
+    }
+
+    private void executeTearDownCallback() {
+        if (this.tearDownCallback != null) {
+            try {
+                this.tearDownCallback.execute(this);
+            } catch (Throwable ex) {
+                throw new RuntimeException("Executing setup callback failed.", ex);
+            }
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContextCallback.java b/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContextCallback.java
new file mode 100644
index 0000000..913b832
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/junit/SlingContextCallback.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.junit;
+
+import java.io.IOException;
+
+import org.apache.sling.api.resource.PersistenceException;
+
+/**
+ * Callback-interface for application-specific setup and teardown operations to
+ * customize the {@link AemContext} JUnit rule.
+ */
+public interface SlingContextCallback {
+
+    /**
+     * Execute callback action
+     * @param context Sling context
+     */
+    void execute(SlingContext context) throws IOException, PersistenceException;
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/junit/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/junit/package-info.java
new file mode 100644
index 0000000..d30c3d0
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/junit/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/**
+ * Rule for providing easy access to Sling context in JUnit tests.
+ */
+package org.apache.sling.testing.mock.sling.junit;
+
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/loader/ContentLoader.java b/src/main/java/org/apache/sling/testing/mock/sling/loader/ContentLoader.java
new file mode 100644
index 0000000..b434604
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/loader/ContentLoader.java
@@ -0,0 +1,586 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.loader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.commons.json.JSONArray;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.commons.json.jcr.JsonItemWriter;
+import org.apache.sling.commons.mime.MimeTypeService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Imports JSON data and binary data into Sling resource hierarchy.
+ */
+public final class ContentLoader {
+
+    private static final String REFERENCE = "jcr:reference:";
+    private static final String PATH = "jcr:path:";
+    private static final String CONTENTTYPE_OCTET_STREAM = "application/octet-stream";
+
+    private static final Set<String> IGNORED_NAMES = ImmutableSet.of(JcrConstants.JCR_PRIMARYTYPE,
+            JcrConstants.JCR_MIXINTYPES, JcrConstants.JCR_UUID, JcrConstants.JCR_BASEVERSION,
+            JcrConstants.JCR_PREDECESSORS, JcrConstants.JCR_SUCCESSORS, JcrConstants.JCR_CREATED, "jcr:checkedOut");
+
+    private final ResourceResolver resourceResolver;
+    private final BundleContext bundleContext;
+    private final DateFormat calendarFormat;
+
+    /**
+     * @param resourceResolver Resource resolver
+     */
+    public ContentLoader(ResourceResolver resourceResolver) {
+        this(resourceResolver, null);
+    }
+
+    /**
+     * @param resourceResolver Resource resolver
+     * @param bundleContext Bundle context
+     */
+    public ContentLoader(ResourceResolver resourceResolver, BundleContext bundleContext) {
+        this.resourceResolver = resourceResolver;
+        this.bundleContext = bundleContext;
+        this.calendarFormat = new SimpleDateFormat(JsonItemWriter.ECMA_DATE_FORMAT, JsonItemWriter.DATE_FORMAT_LOCALE);
+    }
+
+    /**
+     * Import content of JSON file into repository.
+     * @param classpathResource Classpath resource URL for JSON content
+     * @param parentResource Parent resource
+     * @param childName Name of child resource to create with JSON content
+     * @return Resource
+     */
+    public Resource json(String classpathResource, Resource parentResource, String childName) {
+        InputStream is = ContentLoader.class.getResourceAsStream(classpathResource);
+        if (is == null) {
+            throw new IllegalArgumentException("Classpath resource not found: " + classpathResource);
+        }
+        try {
+            return json(is, parentResource, childName);
+        } finally {
+            try {
+                is.close();
+            } catch (IOException ex) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Import content of JSON file into repository. Auto-creates parent
+     * hierarchies as nt:unstrucured nodes if missing.
+     * @param classpathResource Classpath resource URL for JSON content
+     * @param destPath Path to import the JSON content to
+     * @return Resource
+     */
+    public Resource json(String classpathResource, String destPath) {
+        InputStream is = ContentLoader.class.getResourceAsStream(classpathResource);
+        if (is == null) {
+            throw new IllegalArgumentException("Classpath resource not found: " + classpathResource);
+        }
+        try {
+            return json(is, destPath);
+        } finally {
+            try {
+                is.close();
+            } catch (IOException ex) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Import content of JSON file into repository.
+     * @param inputStream Input stream with JSON content
+     * @param parentResource Parent resource
+     * @param childName Name of child resource to create with JSON content
+     * @return Resource
+     */
+    public Resource json(InputStream inputStream, Resource parentResource, String childName) {
+        return json(inputStream, parentResource.getPath() + "/" + childName);
+    }
+
+    /**
+     * Import content of JSON file into repository. Auto-creates parent
+     * hierarchies as nt:unstrucured nodes if missing.
+     * @param inputStream Input stream with JSON content
+     * @param destPath Path to import the JSON content to
+     * @return Resource
+     */
+    public Resource json(InputStream inputStream, String destPath) {
+        try {
+            String parentPath = ResourceUtil.getParent(destPath);
+            String childName = ResourceUtil.getName(destPath);
+
+            Resource parentResource = resourceResolver.getResource(parentPath);
+            if (parentResource == null) {
+                parentResource = createResourceHierarchy(parentPath);
+            }
+            if (parentResource.getChild(childName) != null) {
+                throw new IllegalArgumentException("Resource does already exist: " + destPath);
+            }
+
+            String jsonString = convertToJsonString(inputStream).trim();
+            JSONObject json = new JSONObject(jsonString);
+            return this.createResource(parentResource, childName, json);
+        } catch (JSONException ex) {
+            throw new RuntimeException(ex);
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private Resource createResourceHierarchy(String path) {
+        String parentPath = ResourceUtil.getParent(path);
+        if (parentPath == null) {
+            return null;
+        }
+        Resource parentResource = resourceResolver.getResource(parentPath);
+        if (parentResource == null) {
+            parentResource = createResourceHierarchy(parentPath);
+        }
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
+        try {
+            return resourceResolver.create(parentResource, ResourceUtil.getName(path), props);
+        } catch (PersistenceException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private Resource createResource(Resource parentResource, String childName, JSONObject jsonObject)
+            throws IOException, JSONException {
+
+        // collect all properties first
+        Map<String, Object> props = new HashMap<String, Object>();
+        JSONArray names = jsonObject.names();
+        for (int i = 0; names != null && i < names.length(); i++) {
+            final String name = names.getString(i);
+            if (!IGNORED_NAMES.contains(name)) {
+                Object obj = jsonObject.get(name);
+                if (!(obj instanceof JSONObject)) {
+                    this.setProperty(props, name, obj);
+                }
+            }
+        }
+
+        // validate JCR primary type
+        Object primaryTypeObj = jsonObject.opt(JcrConstants.JCR_PRIMARYTYPE);
+        String primaryType = null;
+        if (primaryTypeObj != null) {
+            primaryType = String.valueOf(primaryTypeObj);
+        }
+        if (primaryType == null) {
+            primaryType = JcrConstants.NT_UNSTRUCTURED;
+        }
+        props.put(JcrConstants.JCR_PRIMARYTYPE, primaryType);
+
+        // create resource
+        Resource resource = resourceResolver.create(parentResource, childName, props);
+
+        // add child resources
+        for (int i = 0; names != null && i < names.length(); i++) {
+            final String name = names.getString(i);
+            if (!IGNORED_NAMES.contains(name)) {
+                Object obj = jsonObject.get(name);
+                if (obj instanceof JSONObject) {
+                    createResource(resource, name, (JSONObject) obj);
+                }
+            }
+        }
+
+        return resource;
+    }
+
+    private void setProperty(Map<String, Object> props, String name, Object value) throws JSONException {
+        if (value instanceof JSONArray) {
+            // multivalue
+            final JSONArray array = (JSONArray) value;
+            if (array.length() > 0) {
+                final Object[] values = new Object[array.length()];
+                for (int i = 0; i < array.length(); i++) {
+                    values[i] = array.get(i);
+                }
+
+                if (values[0] instanceof Double || values[0] instanceof Float) {
+                    Double[] arrayValues = new Double[values.length];
+                    for (int i = 0; i < values.length; i++) {
+                        arrayValues[i] = (Double) values[i];
+                    }
+                    props.put(cleanupJsonName(name), arrayValues);
+                } else if (values[0] instanceof Number) {
+                    Long[] arrayValues = new Long[values.length];
+                    for (int i = 0; i < values.length; i++) {
+                        arrayValues[i] = ((Number) values[i]).longValue();
+                    }
+                    props.put(cleanupJsonName(name), arrayValues);
+                } else if (values[0] instanceof Boolean) {
+                    Boolean[] arrayValues = new Boolean[values.length];
+                    for (int i = 0; i < values.length; i++) {
+                        arrayValues[i] = (Boolean) values[i];
+                    }
+                    props.put(cleanupJsonName(name), arrayValues);
+                } else {
+                    String[] arrayValues = new String[values.length];
+                    for (int i = 0; i < values.length; i++) {
+                        arrayValues[i] = values[i].toString();
+                    }
+                    props.put(cleanupJsonName(name), arrayValues);
+                }
+            } else {
+                props.put(cleanupJsonName(name), new String[0]);
+            }
+
+        } else {
+            // single value
+            if (value instanceof Double || value instanceof Float) {
+                props.put(cleanupJsonName(name), value);
+            } else if (value instanceof Number) {
+                props.put(cleanupJsonName(name), ((Number) value).longValue());
+            } else if (value instanceof Boolean) {
+                props.put(cleanupJsonName(name), value);
+            } else {
+                String stringValue = value.toString();
+
+                // check if value is a Calendar object
+                Calendar calendar = tryParseCalendarValue(stringValue);
+                if (calendar != null) {
+                    props.put(cleanupJsonName(name), calendar);
+                } else {
+                    props.put(cleanupJsonName(name), stringValue);
+                }
+
+            }
+        }
+    }
+
+    private String cleanupJsonName(String name) {
+        if (name.startsWith(REFERENCE)) {
+            return name.substring(REFERENCE.length());
+        }
+        if (name.startsWith(PATH)) {
+            return name.substring(PATH.length());
+        }
+        return name;
+    }
+
+    private String convertToJsonString(InputStream inputStream) {
+        try {
+            return IOUtils.toString(inputStream);
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        } finally {
+            try {
+                inputStream.close();
+            } catch (IOException ex) {
+                // ignore
+            }
+        }
+    }
+
+    private Calendar tryParseCalendarValue(String value) {
+        if (StringUtils.isNotBlank(value)) {
+            synchronized (calendarFormat) {
+                try {
+                    Date date = calendarFormat.parse(value);
+                    Calendar calendar = Calendar.getInstance();
+                    calendar.setTime(date);
+                    return calendar;
+                } catch (ParseException ex) {
+                    // ignore
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Import binary file as nt:file binary node into repository. Auto-creates
+     * parent hierarchies as nt:unstrucured nodes if missing. Mime type is
+     * auto-detected from resource name.
+     * @param classpathResource Classpath resource URL for binary file.
+     * @param path Path to mount binary data to (parent nodes created
+     *            automatically)
+     * @return Resource with binary data
+     */
+    public Resource binaryFile(String classpathResource, String path) {
+        InputStream is = ContentLoader.class.getResourceAsStream(classpathResource);
+        if (is == null) {
+            throw new IllegalArgumentException("Classpath resource not found: " + classpathResource);
+        }
+        try {
+            return binaryFile(is, path, detectMimeTypeFromName(path));
+        } finally {
+            try {
+                is.close();
+            } catch (IOException ex) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Import binary file as nt:file binary node into repository. Auto-creates
+     * parent hierarchies as nt:unstrucured nodes if missing.
+     * @param classpathResource Classpath resource URL for binary file.
+     * @param path Path to mount binary data to (parent nodes created
+     *            automatically)
+     * @param mimeType Mime type of binary data
+     * @return Resource with binary data
+     */
+    public Resource binaryFile(String classpathResource, String path, String mimeType) {
+        InputStream is = ContentLoader.class.getResourceAsStream(classpathResource);
+        if (is == null) {
+            throw new IllegalArgumentException("Classpath resource not found: " + classpathResource);
+        }
+        try {
+            return binaryFile(is, path, mimeType);
+        } finally {
+            try {
+                is.close();
+            } catch (IOException ex) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Import binary file as nt:file binary node into repository. Auto-creates
+     * parent hierarchies as nt:unstrucured nodes if missing. Mime type is
+     * auto-detected from resource name.
+     * @param inputStream Input stream for binary data
+     * @param path Path to mount binary data to (parent nodes created
+     *            automatically)
+     * @return Resource with binary data
+     */
+    public Resource binaryFile(InputStream inputStream, String path) {
+        return binaryFile(inputStream, path, detectMimeTypeFromName(path));
+    }
+
+    /**
+     * Import binary file as nt:file binary node into repository. Auto-creates
+     * parent hierarchies as nt:unstrucured nodes if missing.
+     * @param inputStream Input stream for binary data
+     * @param path Path to mount binary data to (parent nodes created
+     *            automatically)
+     * @param mimeType Mime type of binary data
+     * @return Resource with binary data
+     */
+    public Resource binaryFile(InputStream inputStream, String path, String mimeType) {
+        String parentPath = ResourceUtil.getParent(path, 1);
+        String name = ResourceUtil.getName(path);
+        Resource parentResource = resourceResolver.getResource(parentPath);
+        if (parentResource == null) {
+            parentResource = createResourceHierarchy(parentPath);
+        }
+        return binaryFile(inputStream, parentResource, name, mimeType);
+    }
+
+    /**
+     * Import binary file as nt:file binary node into repository. Auto-creates
+     * parent hierarchies as nt:unstrucured nodes if missing. Mime type is
+     * auto-detected from resource name.
+     * @param inputStream Input stream for binary data
+     * @param parentResource Parent resource
+     * @param name Resource name for nt:file
+     * @return Resource with binary data
+     */
+    public Resource binaryFile(InputStream inputStream, Resource parentResource, String name) {
+        return binaryFile(inputStream, parentResource, name, detectMimeTypeFromName(name));
+    }
+
+    /**
+     * Import binary file as nt:file binary node into repository. Auto-creates
+     * parent hierarchies as nt:unstrucured nodes if missing.
+     * @param inputStream Input stream for binary data
+     * @param parentResource Parent resource
+     * @param name Resource name for nt:file
+     * @param mimeType Mime type of binary data
+     * @return Resource with binary data
+     */
+    public Resource binaryFile(InputStream inputStream, Resource parentResource, String name, String mimeType) {
+        try {
+            Resource file = resourceResolver.create(parentResource, name,
+                    ImmutableMap.<String, Object> builder().put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_FILE)
+                            .build());
+            resourceResolver.create(file, JcrConstants.JCR_CONTENT,
+                    ImmutableMap.<String, Object> builder().put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_RESOURCE)
+                            .put(JcrConstants.JCR_DATA, inputStream).put(JcrConstants.JCR_MIMETYPE, mimeType).build());
+            return file;
+        } catch (PersistenceException ex) {
+            throw new RuntimeException("Unable to create resource at " + parentResource.getPath() + "/" + name, ex);
+        }
+    }
+
+    /**
+     * Import binary file as nt:resource binary node into repository.
+     * Auto-creates parent hierarchies as nt:unstrucured nodes if missing. Mime
+     * type is auto-detected from resource name.
+     * @param classpathResource Classpath resource URL for binary file.
+     * @param path Path to mount binary data to (parent nodes created
+     *            automatically)
+     * @return Resource with binary data
+     */
+    public Resource binaryResource(String classpathResource, String path) {
+        InputStream is = ContentLoader.class.getResourceAsStream(classpathResource);
+        if (is == null) {
+            throw new IllegalArgumentException("Classpath resource not found: " + classpathResource);
+        }
+        try {
+            return binaryResource(is, path, detectMimeTypeFromName(path));
+        } finally {
+            try {
+                is.close();
+            } catch (IOException ex) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Import binary file as nt:resource binary node into repository.
+     * Auto-creates parent hierarchies as nt:unstrucured nodes if missing.
+     * @param classpathResource Classpath resource URL for binary file.
+     * @param path Path to mount binary data to (parent nodes created
+     *            automatically)
+     * @param mimeType Mime type of binary data
+     * @return Resource with binary data
+     */
+    public Resource binaryResource(String classpathResource, String path, String mimeType) {
+        InputStream is = ContentLoader.class.getResourceAsStream(classpathResource);
+        if (is == null) {
+            throw new IllegalArgumentException("Classpath resource not found: " + classpathResource);
+        }
+        try {
+            return binaryResource(is, path, mimeType);
+        } finally {
+            try {
+                is.close();
+            } catch (IOException ex) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Import binary file as nt:resource binary node into repository.
+     * Auto-creates parent hierarchies as nt:unstrucured nodes if missing. Mime
+     * type is auto-detected from resource name.
+     * @param inputStream Input stream for binary data
+     * @param path Path to mount binary data to (parent nodes created
+     *            automatically)
+     * @return Resource with binary data
+     */
+    public Resource binaryResource(InputStream inputStream, String path) {
+        return binaryResource(inputStream, path, detectMimeTypeFromName(path));
+    }
+
+    /**
+     * Import binary file as nt:resource binary node into repository.
+     * Auto-creates parent hierarchies as nt:unstrucured nodes if missing.
+     * @param inputStream Input stream for binary data
+     * @param path Path to mount binary data to (parent nodes created
+     *            automatically)
+     * @param mimeType Mime type of binary data
+     * @return Resource with binary data
+     */
+    public Resource binaryResource(InputStream inputStream, String path, String mimeType) {
+        String parentPath = ResourceUtil.getParent(path, 1);
+        String name = ResourceUtil.getName(path);
+        Resource parentResource = resourceResolver.getResource(parentPath);
+        if (parentResource == null) {
+            parentResource = createResourceHierarchy(parentPath);
+        }
+        return binaryResource(inputStream, parentResource, name, mimeType);
+    }
+
+    /**
+     * Import binary file as nt:resource binary node into repository.
+     * Auto-creates parent hierarchies as nt:unstrucured nodes if missing. Mime
+     * type is auto-detected from resource name.
+     * @param inputStream Input stream for binary data
+     * @param parentResource Parent resource
+     * @param name Resource name for nt:resource
+     * @return Resource with binary data
+     */
+    public Resource binaryResource(InputStream inputStream, Resource parentResource, String name) {
+        return binaryResource(inputStream, parentResource, name, detectMimeTypeFromName(name));
+    }
+
+    /**
+     * Import binary file as nt:resource binary node into repository.
+     * Auto-creates parent hierarchies as nt:unstrucured nodes if missing.
+     * @param inputStream Input stream for binary data
+     * @param parentResource Parent resource
+     * @param name Resource name for nt:resource
+     * @param mimeType Mime type of binary data
+     * @return Resource with binary data
+     */
+    public Resource binaryResource(InputStream inputStream, Resource parentResource, String name, String mimeType) {
+        try {
+            return resourceResolver.create(parentResource, name,
+                    ImmutableMap.<String, Object> builder().put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_RESOURCE)
+                            .put(JcrConstants.JCR_DATA, inputStream).put(JcrConstants.JCR_MIMETYPE, mimeType).build());
+        } catch (PersistenceException ex) {
+            throw new RuntimeException("Unable to create resource at " + parentResource.getPath() + "/" + name, ex);
+        }
+    }
+
+    /**
+     * Detected mime type from name (file extension) using Mime Type service.
+     * Fallback to application/octet-stream.
+     * @param name Node name
+     * @return Mime type (never null)
+     */
+    private String detectMimeTypeFromName(String name) {
+        String mimeType = null;
+        String fileExtension = StringUtils.substringAfterLast(name, ".");
+        if (bundleContext != null && StringUtils.isNotEmpty(fileExtension)) {
+            ServiceReference ref = bundleContext.getServiceReference(MimeTypeService.class.getName());
+            if (ref != null) {
+                MimeTypeService mimeTypeService = (MimeTypeService) bundleContext.getService(ref);
+                mimeType = mimeTypeService.getMimeType(fileExtension);
+            }
+        }
+        return StringUtils.defaultString(mimeType, CONTENTTYPE_OCTET_STREAM);
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java
new file mode 100644
index 0000000..ebe7af5
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/loader/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/**
+ * Helpers for importing test content into the mocked repositories / resource hierarchies.
+ */
+package org.apache.sling.testing.mock.sling.loader;
+
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/package-info.java
new file mode 100644
index 0000000..5919826
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/**
+ * Mock implementation of selected Sling APIs.
+ */
+package org.apache.sling.testing.mock.sling;
+
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/services/MockMimeTypeService.java b/src/main/java/org/apache/sling/testing/mock/sling/services/MockMimeTypeService.java
new file mode 100644
index 0000000..fbc6fb7
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/services/MockMimeTypeService.java
@@ -0,0 +1,78 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.services;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.mime.MimeTypeService;
+import org.apache.sling.commons.mime.internal.MimeTypeServiceImpl;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
+import org.osgi.service.component.ComponentContext;
+
+/**
+ * Mock {@link MimeTypeService} implementation.
+ */
+@Component(inherit = false)
+@Service(MimeTypeService.class)
+public final class MockMimeTypeService extends MimeTypeServiceImpl {
+
+    private boolean initialized;
+
+    /**
+     * Do lazy initializing because reading to avoid reading all defined mime
+     * types from disk if not required
+     */
+    private void lazyInitialization() {
+        if (!this.initialized) {
+            this.initialized = true;
+            // activate service in simulated OSGi environment
+            ComponentContext componentContext = MockOsgi.newComponentContext();
+            this.bindLogService(MockOsgi.newLogService(getClass()));
+            activate(componentContext);
+        }
+    }
+
+    @Override
+    public String getMimeType(final String name) {
+        lazyInitialization();
+        return super.getMimeType(name);
+    }
+
+    @Override
+    public String getExtension(final String mimeType) {
+        lazyInitialization();
+        return super.getExtension(mimeType);
+    }
+
+    @Override
+    public void registerMimeType(final String mimeType, final String... extensions) {
+        lazyInitialization();
+        super.registerMimeType(mimeType, extensions);
+    }
+
+    @Override
+    public void registerMimeType(final InputStream mimeTabStream) throws IOException {
+        lazyInitialization();
+        super.registerMimeType(mimeTabStream);
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/services/MockModelAdapterFactory.java b/src/main/java/org/apache/sling/testing/mock/sling/services/MockModelAdapterFactory.java
new file mode 100644
index 0000000..c116b18
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/services/MockModelAdapterFactory.java
@@ -0,0 +1,295 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.services;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.adapter.AdapterFactory;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.impl.ModelAdapterFactory;
+import org.apache.sling.models.spi.ImplementationPicker;
+import org.apache.sling.models.spi.Injector;
+import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+import org.osgi.service.component.ComponentContext;
+import org.reflections.Reflections;
+
+/**
+ * Mock {@link ModelAdapterFactory} implementation.
+ */
+@Component(inherit = false)
+@Service(AdapterFactory.class)
+public final class MockModelAdapterFactory extends ModelAdapterFactory {
+
+    private final BundleContext bundleContext;
+
+    /**
+     * @param componentContext OSGi component context
+     */
+    public MockModelAdapterFactory(ComponentContext componentContext) {
+        bundleContext = componentContext.getBundleContext();
+
+        // register service listener to collect injectors
+        // this allows detecting injectors even if they are registered after
+        // this bundle
+        // (which is otherwise currently not supported in the osgi mock
+        // environment)
+        bundleContext.addServiceListener(new InjectorServiceListener());
+
+        // activate service in simulated OSGi environment
+        activate(componentContext);
+    }
+
+    /**
+     * Constructor with default component context
+     */
+    public MockModelAdapterFactory() {
+        this(MockOsgi.newComponentContext());
+    }
+
+    private class InjectorServiceListener implements ServiceListener {
+
+        @Override
+        public void serviceChanged(ServiceEvent event) {
+            Object service = bundleContext.getService(event.getServiceReference());
+            if (service instanceof Injector) {
+                if (event.getType() == ServiceEvent.REGISTERED) {
+                    bindInjector((Injector) service, getServiceProperties(event.getServiceReference()));
+                } else if (event.getType() == ServiceEvent.UNREGISTERING) {
+                    unbindInjector((Injector) service, getServiceProperties(event.getServiceReference()));
+                }
+            }
+            if (service instanceof InjectAnnotationProcessorFactory) {
+                if (event.getType() == ServiceEvent.REGISTERED) {
+                    bindInjectAnnotationProcessorFactory((InjectAnnotationProcessorFactory) service,
+                            getServiceProperties(event.getServiceReference()));
+                } else if (event.getType() == ServiceEvent.UNREGISTERING) {
+                    unbindInjectAnnotationProcessorFactory((InjectAnnotationProcessorFactory) service,
+                            getServiceProperties(event.getServiceReference()));
+                }
+            }
+            if (service instanceof ImplementationPicker) {
+                if (event.getType() == ServiceEvent.REGISTERED) {
+                    bindImplementationPicker((ImplementationPicker) service,
+                            getServiceProperties(event.getServiceReference()));
+                } else if (event.getType() == ServiceEvent.UNREGISTERING) {
+                    unbindImplementationPicker((ImplementationPicker) service,
+                            getServiceProperties(event.getServiceReference()));
+                }
+            }
+        }
+
+        private Map<String, Object> getServiceProperties(ServiceReference reference) {
+            Map<String, Object> props = new HashMap<String, Object>();
+            String[] propertyKeys = reference.getPropertyKeys();
+            for (String key : propertyKeys) {
+                props.put(key, reference.getProperty(key));
+            }
+            return props;
+        }
+
+    }
+
+    /**
+     * Scan classpaths for given package name (and sub packages) to scan for and
+     * register all classes with @Model annotation.
+     * @param packageName Java package name
+     */
+    public void addModelsForPackage(String packageName) {
+        Bundle bundle = new ModelsPackageBundle(packageName, Bundle.ACTIVE);
+        BundleEvent event = new BundleEvent(BundleEvent.STARTED, bundle);
+        MockOsgi.sendBundleEvent(this.bundleContext, event);
+    }
+
+    @SuppressWarnings("unused")
+    private class ModelsPackageBundle implements Bundle {
+
+        private final String packageName;
+        private final int state;
+
+        public ModelsPackageBundle(String packageName, int state) {
+            this.packageName = packageName;
+            this.state = state;
+        }
+
+        @Override
+        public int getState() {
+            return this.state;
+        }
+
+        @Override
+        public Dictionary getHeaders() {
+            Dictionary<String, Object> headers = new Hashtable<String, Object>();
+            headers.put("Sling-Model-Packages", this.packageName);
+            return headers;
+        }
+
+        @Override
+        public Enumeration findEntries(String path, String filePattern, boolean recurse) {
+            Reflections reflections = new Reflections(this.packageName);
+            Set<Class<?>> types = reflections.getTypesAnnotatedWith(Model.class);
+            Vector<URL> urls = new Vector<URL>(); // NOPMD
+            try {
+                for (Class<?> type : types) {
+                    urls.add(new URL("file:/" + type.getName().replace('.', '/') + ".class"));
+                }
+            } catch (MalformedURLException ex) {
+                throw new RuntimeException("Malformed URL.", ex);
+            }
+            return urls.elements();
+        }
+
+        @Override
+        public Class loadClass(String name) throws ClassNotFoundException {
+            return getClass().getClassLoader().loadClass(name);
+        }
+
+        @Override
+        public BundleContext getBundleContext() {
+            return bundleContext;
+        }
+
+        @Override
+        public void start(int options) throws BundleException {
+            // do nothing
+        }
+
+        @Override
+        public void start() throws BundleException {
+            // do nothing
+        }
+
+        @Override
+        public void stop(int options) throws BundleException {
+            // do nothing
+        }
+
+        @Override
+        public void stop() throws BundleException {
+            // do nothing
+        }
+
+        @Override
+        public void update(InputStream input) throws BundleException {
+            // do nothing
+        }
+
+        @Override
+        public void update() throws BundleException {
+            // do nothing
+        }
+
+        @Override
+        public void uninstall() throws BundleException {
+            // do nothing
+        }
+
+        @Override
+        public long getBundleId() {
+            return 0;
+        }
+
+        @Override
+        public String getLocation() {
+            return null;
+        }
+
+        @Override
+        public ServiceReference[] getRegisteredServices() { // NOPMD
+            return null;
+        }
+
+        @Override
+        public ServiceReference[] getServicesInUse() { // NOPMD
+            return null;
+        }
+
+        @Override
+        public boolean hasPermission(Object permission) {
+            return false;
+        }
+
+        @Override
+        public URL getResource(String name) {
+            return null;
+        }
+
+        @Override
+        public Dictionary getHeaders(String locale) {
+            return null;
+        }
+
+        @Override
+        public String getSymbolicName() {
+            return null;
+        }
+
+        @Override
+        public Enumeration getResources(String name) throws IOException {
+            return null;
+        }
+
+        @Override
+        public Enumeration getEntryPaths(String path) {
+            return null;
+        }
+
+        @Override
+        public URL getEntry(String path) {
+            return null;
+        }
+
+        @Override
+        public long getLastModified() {
+            return 0;
+        }
+
+        // this is part of org.osgi 4.2.0
+        public Map getSignerCertificates(int signersType) {
+            return null;
+        }
+
+        // this is part of org.osgi 4.2.0
+        public Version getVersion() {
+            return null;
+        }
+
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/services/MockSlingSettingService.java b/src/main/java/org/apache/sling/testing/mock/sling/services/MockSlingSettingService.java
new file mode 100644
index 0000000..671b812
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/services/MockSlingSettingService.java
@@ -0,0 +1,90 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.services;
+
+import java.net.URL;
+import java.util.Set;
+
+import org.apache.sling.settings.SlingSettingsService;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Mock implementation of {@link SlingSettingsService}.
+ */
+public final class MockSlingSettingService implements SlingSettingsService {
+
+    private Set<String> runModes;
+
+    /**
+     * Instantiate with no default run modes.
+     */
+    public MockSlingSettingService() {
+        this(ImmutableSet.<String> of());
+    }
+
+    /**
+     * Instantiate with given run modes
+     * @param defaultRunModes Run modes
+     */
+    public MockSlingSettingService(Set<String> defaultRunModes) {
+        this.runModes = defaultRunModes;
+    }
+
+    @Override
+    public Set<String> getRunModes() {
+        return ImmutableSet.copyOf(this.runModes);
+    }
+
+    public void setRunModes(Set<String> runModes) {
+        this.runModes = runModes;
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public String getAbsolutePathWithinSlingHome(String relativePath) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getSlingId() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getSlingHomePath() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public URL getSlingHome() {
+        throw new UnsupportedOperationException();
+    }
+
+    // part of Sling API 2.7
+    public String getSlingName() {
+        throw new UnsupportedOperationException();
+    }
+
+    // part of Sling API 2.7
+    public String getSlingDescription() {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/servlet/CookieSupport.java b/src/main/java/org/apache/sling/testing/mock/sling/servlet/CookieSupport.java
new file mode 100644
index 0000000..ef7c171
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/servlet/CookieSupport.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.servlet;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.servlet.http.Cookie;
+
+/**
+ * Manages cookies for request and response.
+ */
+class CookieSupport {
+
+    private Map<String, Cookie> cookies = new LinkedHashMap<String, Cookie>();
+
+    public void addCookie(Cookie cookie) {
+        cookies.put(cookie.getName(), cookie);
+    }
+
+    public Cookie getCookie(String name) {
+        return cookies.get(name);
+    }
+
+    public Cookie[] getCookies() {
+        if (cookies.isEmpty()) {
+            return null;
+        } else {
+            return cookies.values().toArray(new Cookie[cookies.size()]);
+        }
+    }
+
+    public void reset() {
+        cookies.clear();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/servlet/HeaderSupport.java b/src/main/java/org/apache/sling/testing/mock/sling/servlet/HeaderSupport.java
new file mode 100644
index 0000000..cc91c93
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/servlet/HeaderSupport.java
@@ -0,0 +1,175 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.servlet;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.Vector;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+
+/**
+ * Manage HTTP headers for request and response.
+ */
+class HeaderSupport {
+
+    private static final String RFC_1123_DATE_PATTERN = "EEE, dd MMM yyyy HH:mm:ss z";
+    private static final DateFormat RFC1123_DATE_FORMAT = new SimpleDateFormat(RFC_1123_DATE_PATTERN, Locale.US);
+    private static final TimeZone TIMEZONE_GMT = TimeZone.getTimeZone("GMT");
+    static {
+        RFC1123_DATE_FORMAT.setTimeZone(TIMEZONE_GMT);
+    }
+
+    private List<HeaderValue> headers = new ArrayList<HeaderValue>();
+
+    private static class HeaderValue {
+
+        private String key;
+        private String value;
+
+        public HeaderValue(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        public String getKey() {
+            return this.key;
+        }
+
+        public String getValue() {
+            return this.value;
+        }
+
+    }
+
+    public void addHeader(String name, String value) {
+        headers.add(new HeaderValue(name, value));
+    }
+
+    public void addIntHeader(String name, int value) {
+        headers.add(new HeaderValue(name, Integer.toString(value)));
+    }
+
+    public void addDateHeader(String name, long date) {
+        Calendar calendar = Calendar.getInstance(TIMEZONE_GMT, Locale.US);
+        calendar.setTimeInMillis(date);
+        headers.add(new HeaderValue(name, formatDate(calendar)));
+    }
+
+    public void setHeader(String name, String value) {
+        removeHeaders(name);
+        addHeader(name, value);
+    }
+
+    public void setIntHeader(String name, int value) {
+        removeHeaders(name);
+        addIntHeader(name, value);
+    }
+
+    public void setDateHeader(String name, long date) {
+        removeHeaders(name);
+        addDateHeader(name, date);
+    }
+
+    private void removeHeaders(String name) {
+        for (int i = this.headers.size() - 1; i >= 0; i--) {
+            if (StringUtils.equals(this.headers.get(i).getKey(), name)) {
+                headers.remove(i);
+            }
+        }
+    }
+
+    public boolean containsHeader(String name) {
+        return !getHeaders(name).isEmpty();
+    }
+
+    public String getHeader(String name) {
+        Collection<String> values = getHeaders(name);
+        if (!values.isEmpty()) {
+            return values.iterator().next();
+        } else {
+            return null;
+        }
+    }
+
+    public int getIntHeader(String name) {
+        String value = getHeader(name);
+        return NumberUtils.toInt(value);
+    }
+
+    public long getDateHeader(String name) {
+        String value = getHeader(name);
+        if (StringUtils.isEmpty(value)) {
+            return 0L;
+        } else {
+            try {
+                return parseDate(value).getTimeInMillis();
+            } catch (ParseException ex) {
+                return 0L;
+            }
+        }
+    }
+
+    public Collection<String> getHeaders(String name) {
+        List<String> values = new ArrayList<String>();
+        for (HeaderValue entry : headers) {
+            if (StringUtils.equals(entry.getKey(), name)) {
+                values.add(entry.getValue());
+            }
+        }
+        return values;
+    }
+
+    public Collection<String> getHeaderNames() {
+        Set<String> values = new HashSet<String>();
+        for (HeaderValue entry : headers) {
+            values.add(entry.getKey());
+        }
+        return values;
+    }
+
+    public void reset() {
+        headers.clear();
+    }
+
+    public static Enumeration<String> toEnumeration(Collection<String> collection) {
+        return new Vector<String>(collection).elements();
+    }
+
+    private static synchronized String formatDate(Calendar date) {
+        return RFC1123_DATE_FORMAT.format(date.getTime());
+    }
+
+    private static synchronized Calendar parseDate(String dateString) throws ParseException {
+        RFC1123_DATE_FORMAT.parse(dateString);
+        return RFC1123_DATE_FORMAT.getCalendar();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockHttpSession.java b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockHttpSession.java
new file mode 100644
index 0000000..f877441
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockHttpSession.java
@@ -0,0 +1,129 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.servlet;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.collections.IteratorUtils;
+
+/**
+ * Mock {@link HttpSession} implementation.
+ */
+public final class MockHttpSession implements HttpSession {
+
+    private final ServletContext servletContext = new MockServletContext();
+    private final Map<String, Object> attributeMap = new HashMap<String, Object>();
+    private final String sessionID = UUID.randomUUID().toString();
+    private final long creationTime = System.currentTimeMillis();
+
+    @Override
+    public ServletContext getServletContext() {
+        return this.servletContext;
+    }
+
+    @Override
+    public Object getAttribute(final String name) {
+        return this.attributeMap.get(name);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Enumeration<String> getAttributeNames() {
+        return IteratorUtils.asEnumeration(this.attributeMap.keySet().iterator());
+    }
+
+    @Override
+    public String getId() {
+        return this.sessionID;
+    }
+
+    @Override
+    public long getCreationTime() {
+        return this.creationTime;
+    }
+
+    @Override
+    public Object getValue(final String name) {
+        return getAttribute(name);
+    }
+
+    @Override
+    public String[] getValueNames() {
+        return this.attributeMap.keySet().toArray(new String[this.attributeMap.keySet().size()]);
+    }
+
+    @Override
+    public void putValue(final String name, final Object value) {
+        setAttribute(name, value);
+    }
+
+    @Override
+    public void removeAttribute(final String name) {
+        this.attributeMap.remove(name);
+    }
+
+    @Override
+    public void removeValue(final String name) {
+        this.attributeMap.remove(name);
+    }
+
+    @Override
+    public void setAttribute(final String name, final Object value) {
+        this.attributeMap.put(name, value);
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public long getLastAccessedTime() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getMaxInactiveInterval() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public javax.servlet.http.HttpSessionContext getSessionContext() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void invalidate() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isNew() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setMaxInactiveInterval(final int interval) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockRequestPathInfo.java b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockRequestPathInfo.java
new file mode 100644
index 0000000..6e058e4
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockRequestPathInfo.java
@@ -0,0 +1,86 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.servlet;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.request.RequestPathInfo;
+import org.apache.sling.api.resource.Resource;
+
+/**
+ * Mock {@link RequestPathInfo} implementation.
+ */
+public final class MockRequestPathInfo implements RequestPathInfo {
+
+    private String extension;
+    private String resourcePath;
+    private String selectorString;
+    private String suffix;
+
+    @Override
+    public String getExtension() {
+        return this.extension;
+    }
+
+    @Override
+    public String getResourcePath() {
+        return this.resourcePath;
+    }
+
+    @Override
+    public String[] getSelectors() {
+        if (StringUtils.isEmpty(this.selectorString)) {
+            return new String[0];
+        } else {
+            return StringUtils.split(this.selectorString, ".");
+        }
+    }
+
+    @Override
+    public String getSelectorString() {
+        return this.selectorString;
+    }
+
+    @Override
+    public String getSuffix() {
+        return this.suffix;
+    }
+
+    public void setExtension(final String extension) {
+        this.extension = extension;
+    }
+
+    public void setResourcePath(final String resourcePath) {
+        this.resourcePath = resourcePath;
+    }
+
+    public void setSelectorString(final String selectorString) {
+        this.selectorString = selectorString;
+    }
+
+    public void setSuffix(final String suffix) {
+        this.suffix = suffix;
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public Resource getSuffixResource() {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockServletContext.java b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockServletContext.java
new file mode 100644
index 0000000..107c22f
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockServletContext.java
@@ -0,0 +1,301 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.servlet;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.EventListener;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterRegistration;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.ServletRegistration.Dynamic;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.descriptor.JspConfigDescriptor;
+
+/**
+ * Mock {@link ServletContext} implementation.
+ */
+public final class MockServletContext implements ServletContext {
+
+    @Override
+    public String getMimeType(final String file) {
+        return "application/octet-stream";
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public Object getAttribute(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Enumeration<String> getAttributeNames() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServletContext getContext(final String uriPath) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getContextPath() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getInitParameter(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Enumeration<String> getInitParameterNames() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getMajorVersion() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getMinorVersion() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RequestDispatcher getNamedDispatcher(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getRealPath(final String pPath) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RequestDispatcher getRequestDispatcher(final String path) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public URL getResource(final String pPath) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public InputStream getResourceAsStream(final String path) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<String> getResourcePaths(final String path) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getServerInfo() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Servlet getServlet(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getServletContextName() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Enumeration<String> getServletNames() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Enumeration<Servlet> getServlets() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void log(final String msg) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void log(final Exception exception, final String msg) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void log(final String msg, final Throwable throwable) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeAttribute(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setAttribute(final String name, final Object object) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getEffectiveMajorVersion() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getEffectiveMinorVersion() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean setInitParameter(final String name, final String value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Dynamic addServlet(final String servletName, final String className) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Dynamic addServlet(final String servletName, final Servlet servlet) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Dynamic addServlet(final String servletName, final Class<? extends Servlet> servletClass) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T extends Servlet> T createServlet(final Class<T> clazz) throws ServletException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServletRegistration getServletRegistration(final String servletName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<String, ? extends ServletRegistration> getServletRegistrations() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FilterRegistration.Dynamic addFilter(final String filterName, final String className) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FilterRegistration.Dynamic addFilter(final String filterName, final Filter filter) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FilterRegistration.Dynamic addFilter(final String filterName, final Class<? extends Filter> filterClass) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T extends Filter> T createFilter(final Class<T> clazz) throws ServletException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FilterRegistration getFilterRegistration(final String filterName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SessionCookieConfig getSessionCookieConfig() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setSessionTrackingModes(final Set<SessionTrackingMode> sessionTrackingModes) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addListener(final String pClassName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T extends EventListener> void addListener(final T listener) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addListener(final Class<? extends EventListener> listenerClass) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T extends EventListener> T createListener(final Class<T> clazz) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public JspConfigDescriptor getJspConfigDescriptor() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ClassLoader getClassLoader() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void declareRoles(final String... roleNames) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequest.java b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequest.java
new file mode 100644
index 0000000..4444945
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequest.java
@@ -0,0 +1,696 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.servlet;
+
+import java.io.BufferedReader;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.Part;
+
+import org.apache.commons.collections.IteratorUtils;
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.adapter.SlingAdaptable;
+import org.apache.sling.api.request.RequestDispatcherOptions;
+import org.apache.sling.api.request.RequestParameter;
+import org.apache.sling.api.request.RequestParameterMap;
+import org.apache.sling.api.request.RequestPathInfo;
+import org.apache.sling.api.request.RequestProgressTracker;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.servlets.HttpConstants;
+import org.apache.sling.testing.mock.sling.MockSling;
+
+/**
+ * Mock {@link SlingHttpServletRequest} implementation.
+ */
+public class MockSlingHttpServletRequest extends SlingAdaptable implements SlingHttpServletRequest {
+
+    private ResourceResolver resourceResolver;
+    private RequestPathInfo requestPathInfo = new MockRequestPathInfo();
+    private Map<String, Object> attributeMap = new HashMap<String, Object>();
+    private Map<String, String[]> parameterMap = new LinkedHashMap<String, String[]>();
+    private HttpSession session;
+    private Resource resource;
+    private String contextPath;
+    private String queryString;
+    private String scheme = "http";
+    private String serverName = "localhost";
+    private int serverPort = 80;
+    private String method = HttpConstants.METHOD_GET;
+    private final HeaderSupport headerSupport = new HeaderSupport();
+    private final CookieSupport cookieSupport = new CookieSupport();
+
+    /**
+     * Instantiate with default resource resolver
+     */
+    public MockSlingHttpServletRequest() {
+        this.resourceResolver = MockSling.newResourceResolver();
+    }
+
+    /**
+     * @param resourceResolver Resource resolver
+     */
+    public MockSlingHttpServletRequest(ResourceResolver resourceResolver) {
+        this.resourceResolver = resourceResolver;
+    }
+
+    @Override
+    public ResourceResolver getResourceResolver() {
+        return this.resourceResolver;
+    }
+
+    @Override
+    public HttpSession getSession() {
+        return getSession(true);
+    }
+
+    @Override
+    public HttpSession getSession(boolean create) {
+        if (this.session == null && create) {
+            this.session = new MockHttpSession();
+        }
+        return this.session;
+    }
+
+    @Override
+    public RequestPathInfo getRequestPathInfo() {
+        return this.requestPathInfo;
+    }
+
+    @Override
+    public Object getAttribute(String name) {
+        return this.attributeMap.get(name);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Enumeration<String> getAttributeNames() {
+        return IteratorUtils.asEnumeration(this.attributeMap.keySet().iterator());
+    }
+
+    @Override
+    public void removeAttribute(String name) {
+        this.attributeMap.remove(name);
+    }
+
+    @Override
+    public void setAttribute(String name, Object object) {
+        this.attributeMap.put(name, object);
+    }
+
+    @Override
+    public Resource getResource() {
+        return this.resource;
+    }
+
+    public void setResource(Resource resource) {
+        this.resource = resource;
+    }
+
+    @Override
+    public String getParameter(String name) {
+        Object object = this.parameterMap.get(name);
+        if (object instanceof String) {
+            return (String) object;
+        } else if (object instanceof String[]) {
+            String[] values = (String[]) object;
+            if (values.length > 0) {
+                return values[0];
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Map<String, String[]> getParameterMap() {
+        return this.parameterMap;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Enumeration<String> getParameterNames() {
+        return IteratorUtils.asEnumeration(this.parameterMap.keySet().iterator());
+    }
+
+    @Override
+    public String[] getParameterValues(String name) { // NOPMD
+        Object object = this.parameterMap.get(name);
+        if (object instanceof String) {
+            return new String[] { (String) object };
+        } else if (object instanceof String[]) {
+            return (String[]) object;
+        }
+        return null; // NOPMD
+    }
+
+    /**
+     * @param parameterMap Map of parameters
+     */
+    public void setParameterMap(Map<String, Object> parameterMap) {
+        this.parameterMap.clear();
+        for (Map.Entry<String, Object> entry : parameterMap.entrySet()) {
+            String key = entry.getKey();
+            Object value = entry.getValue();
+            if (value instanceof String[]) {
+                this.parameterMap.put(key, (String[]) value);
+            } else if (value != null) {
+                this.parameterMap.put(key, new String[] { value.toString() });
+            } else {
+                this.parameterMap.put(key, null);
+            }
+        }
+        try {
+            this.queryString = formatQueryString(this.parameterMap);
+        } catch (UnsupportedEncodingException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private String formatQueryString(Map<String, String[]> map) throws UnsupportedEncodingException {
+        StringBuilder querystring = new StringBuilder();
+        for (Map.Entry<String, String[]> entry : this.parameterMap.entrySet()) {
+            if (entry.getValue() != null) {
+                for (String value : entry.getValue()) {
+                    if (querystring.length() != 0) {
+                        querystring.append('&');
+                    }
+                    querystring.append(URLEncoder.encode(entry.getKey(), CharEncoding.UTF_8));
+                    querystring.append('=');
+                    if (value != null) {
+                        querystring.append(URLEncoder.encode(value, CharEncoding.UTF_8));
+                    }
+                }
+            }
+        }
+        if (querystring.length() > 0) {
+            return querystring.toString();
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public Locale getLocale() {
+        return Locale.US;
+    }
+
+    @Override
+    public String getContextPath() {
+        return this.contextPath;
+    }
+
+    /**
+     * @param contextPath Webapp context path
+     */
+    public void setContextPath(String contextPath) {
+        this.contextPath = contextPath;
+    }
+
+    /**
+     * @param queryString Query string (with proper URL encoding)
+     */
+    public void setQueryString(String queryString) {
+        this.queryString = queryString;
+        try {
+            parseQueryString(this.parameterMap, this.queryString);
+        } catch (UnsupportedEncodingException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private void parseQueryString(Map<String, String[]> map, String query) throws UnsupportedEncodingException {
+        Map<String, List<String>> queryPairs = new LinkedHashMap<String, List<String>>();
+        String[] pairs = query.split("&");
+        for (String pair : pairs) {
+            int idx = pair.indexOf('=');
+            String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), CharEncoding.UTF_8) : pair;
+            if (!queryPairs.containsKey(key)) {
+                queryPairs.put(key, new ArrayList<String>());
+            }
+            String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1),
+                    CharEncoding.UTF_8) : null;
+            queryPairs.get(key).add(value);
+        }
+        map.clear();
+        for (Map.Entry<String, List<String>> entry : queryPairs.entrySet()) {
+            map.put(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]));
+        }
+    }
+
+    @Override
+    public String getQueryString() {
+        return this.queryString;
+    }
+
+    @Override
+    public String getScheme() {
+        return this.scheme;
+    }
+
+    public void setScheme(String scheme) {
+        this.scheme = scheme;
+    }
+
+    @Override
+    public String getServerName() {
+        return this.serverName;
+    }
+
+    public void setServerName(String serverName) {
+        this.serverName = serverName;
+    }
+
+    @Override
+    public int getServerPort() {
+        return this.serverPort;
+    }
+
+    public void setServerPort(int serverPort) {
+        this.serverPort = serverPort;
+    }
+
+    @Override
+    public boolean isSecure() {
+        return StringUtils.equals("https", getScheme());
+    }
+
+    @Override
+    public String getMethod() {
+        return this.method;
+    }
+
+    public void setMethod(String method) {
+        this.method = method;
+    }
+
+    @Override
+    public long getDateHeader(String name) {
+        return headerSupport.getDateHeader(name);
+    }
+
+    @Override
+    public String getHeader(String name) {
+        return headerSupport.getHeader(name);
+    }
+
+    @Override
+    public Enumeration<String> getHeaderNames() {
+        return HeaderSupport.toEnumeration(headerSupport.getHeaderNames());
+    }
+
+    @Override
+    public Enumeration<String> getHeaders(String name) {
+        return HeaderSupport.toEnumeration(headerSupport.getHeaders(name));
+    }
+
+    @Override
+    public int getIntHeader(String name) {
+        return headerSupport.getIntHeader(name);
+    }
+
+    /**
+     * Add header, keep existing ones with same name.
+     * @param name Header name
+     * @param value Header value
+     */
+    public void addHeader(String name, String value) {
+        headerSupport.addHeader(name, value);
+    }
+
+    /**
+     * Add header, keep existing ones with same name.
+     * @param name Header name
+     * @param value Header value
+     */
+    public void addIntHeader(String name, int value) {
+        headerSupport.addIntHeader(name, value);
+    }
+
+    /**
+     * Add header, keep existing ones with same name.
+     * @param name Header name
+     * @param date Header value
+     */
+    public void addDateHeader(String name, long date) {
+        headerSupport.addDateHeader(name, date);
+    }
+
+    /**
+     * Set header, overwrite existing ones with same name.
+     * @param name Header name
+     * @param value Header value
+     */
+    public void setHeader(String name, String value) {
+        headerSupport.setHeader(name, value);
+    }
+
+    /**
+     * Set header, overwrite existing ones with same name.
+     * @param name Header name
+     * @param value Header value
+     */
+    public void setIntHeader(String name, int value) {
+        headerSupport.setIntHeader(name, value);
+    }
+
+    /**
+     * Set header, overwrite existing ones with same name.
+     * @param name Header name
+     * @param date Header value
+     */
+    public void setDateHeader(String name, long date) {
+        headerSupport.setDateHeader(name, date);
+    }
+
+    @Override
+    public Cookie getCookie(String name) {
+        return cookieSupport.getCookie(name);
+    }
+
+    @Override
+    public Cookie[] getCookies() {
+        return cookieSupport.getCookies();
+    }
+
+    /**
+     * Set cookie
+     * @param cookie Cookie
+     */
+    public void addCookie(Cookie cookie) {
+        cookieSupport.addCookie(cookie);
+    }
+
+    // --- unsupported operations ---
+
+    @Override
+    public RequestDispatcher getRequestDispatcher(Resource dispatcherResource) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RequestDispatcher getRequestDispatcher(String dispatcherPath, RequestDispatcherOptions options) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RequestDispatcher getRequestDispatcher(Resource dispatcherResource, RequestDispatcherOptions options) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RequestParameter getRequestParameter(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RequestParameterMap getRequestParameterMap() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RequestParameter[] getRequestParameters(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RequestProgressTracker getRequestProgressTracker() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ResourceBundle getResourceBundle(Locale pLocale) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ResourceBundle getResourceBundle(String baseName, Locale locale) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getResponseContentType() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Enumeration<String> getResponseContentTypes() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getAuthType() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getPathInfo() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getPathTranslated() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getRemoteUser() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getRequestURI() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public StringBuffer getRequestURL() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getRequestedSessionId() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getServletPath() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Principal getUserPrincipal() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isRequestedSessionIdFromCookie() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isRequestedSessionIdFromURL() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isRequestedSessionIdFromUrl() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isRequestedSessionIdValid() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isUserInRole(String role) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCharacterEncoding() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getContentLength() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getContentType() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServletInputStream getInputStream() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getLocalAddr() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getLocalName() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getLocalPort() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Enumeration<Locale> getLocales() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getProtocol() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public BufferedReader getReader() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getRealPath(String path) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getRemoteAddr() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getRemoteHost() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getRemotePort() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RequestDispatcher getRequestDispatcher(String path) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setCharacterEncoding(String env) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean authenticate(HttpServletResponse response) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void login(String pUsername, String password) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void logout() throws ServletException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Collection<Part> getParts() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Part getPart(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServletContext getServletContext() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public AsyncContext startAsync() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isAsyncStarted() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isAsyncSupported() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public AsyncContext getAsyncContext() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DispatcherType getDispatcherType() {
+        throw new UnsupportedOperationException();
+    }
+
+    // part of Sling API 2.7
+    public List<RequestParameter> getRequestParameterList() {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponse.java b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponse.java
new file mode 100644
index 0000000..b5d918e
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponse.java
@@ -0,0 +1,280 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.servlet;
+
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.Locale;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.adapter.SlingAdaptable;
+
+/**
+ * Mock {@link SlingHttpServletResponse} implementation.
+ */
+public class MockSlingHttpServletResponse extends SlingAdaptable implements SlingHttpServletResponse {
+
+    private static final String CHARSET_SEPARATOR = ";charset=";
+
+    private String contentType;
+    private String characterEncoding = CharEncoding.ISO_8859_1;
+    private int contentLength;
+    private int status = HttpServletResponse.SC_OK;
+    private int bufferSize = 1024 * 8;
+    private boolean isCommitted;
+    private final HeaderSupport headerSupport = new HeaderSupport();
+    private final ResponseBodySupport bodySupport = new ResponseBodySupport();
+    private final CookieSupport cookieSupport = new CookieSupport();
+
+    @Override
+    public String getContentType() {
+        if (this.contentType == null) {
+            return null;
+        } else {
+            return this.contentType
+                    + (StringUtils.isNotBlank(characterEncoding) ? CHARSET_SEPARATOR + characterEncoding : "");
+        }
+    }
+
+    @Override
+    public void setContentType(String type) {
+        this.contentType = type;
+        if (StringUtils.contains(this.contentType, CHARSET_SEPARATOR)) {
+            this.characterEncoding = StringUtils.substringAfter(this.contentType, CHARSET_SEPARATOR);
+            this.contentType = StringUtils.substringBefore(this.contentType, CHARSET_SEPARATOR);
+        }
+    }
+
+    @Override
+    public void setCharacterEncoding(String charset) {
+        this.characterEncoding = charset;
+    }
+
+    @Override
+    public String getCharacterEncoding() {
+        return this.characterEncoding;
+    }
+
+    @Override
+    public void setContentLength(int len) {
+        this.contentLength = len;
+    }
+
+    public int getContentLength() {
+        return this.contentLength;
+    }
+
+    @Override
+    public void setStatus(int sc, String sm) {
+        setStatus(sc);
+    }
+
+    @Override
+    public void setStatus(int sc) {
+        this.status = sc;
+    }
+
+    @Override
+    public int getStatus() {
+        return this.status;
+    }
+
+    @Override
+    public void sendError(int sc, String msg) {
+        setStatus(sc);
+    }
+
+    @Override
+    public void sendError(int sc) {
+        setStatus(sc);
+    }
+
+    @Override
+    public void sendRedirect(String location) {
+        setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+        setHeader("Location", location);
+    }
+
+    @Override
+    public void addHeader(String name, String value) {
+        headerSupport.addHeader(name, value);
+    }
+
+    @Override
+    public void addIntHeader(String name, int value) {
+        headerSupport.addIntHeader(name, value);
+    }
+
+    @Override
+    public void addDateHeader(String name, long date) {
+        headerSupport.addDateHeader(name, date);
+    }
+
+    @Override
+    public void setHeader(String name, String value) {
+        headerSupport.setHeader(name, value);
+    }
+
+    @Override
+    public void setIntHeader(String name, int value) {
+        headerSupport.setIntHeader(name, value);
+    }
+
+    @Override
+    public void setDateHeader(String name, long date) {
+        headerSupport.setDateHeader(name, date);
+    }
+
+    @Override
+    public boolean containsHeader(String name) {
+        return headerSupport.containsHeader(name);
+    }
+
+    @Override
+    public String getHeader(String name) {
+        return headerSupport.getHeader(name);
+    }
+
+    @Override
+    public Collection<String> getHeaders(String name) {
+        return headerSupport.getHeaders(name);
+    }
+
+    @Override
+    public Collection<String> getHeaderNames() {
+        return headerSupport.getHeaderNames();
+    }
+
+    @Override
+    public PrintWriter getWriter() {
+        return bodySupport.getWriter(getCharacterEncoding());
+    }
+
+    @Override
+    public ServletOutputStream getOutputStream() {
+        return bodySupport.getOutputStream();
+    }
+
+    @Override
+    public void reset() {
+        if (isCommitted()) {
+            throw new IllegalStateException("Response already committed.");
+        }
+        bodySupport.reset();
+        headerSupport.reset();
+        cookieSupport.reset();
+        status = HttpServletResponse.SC_OK;
+        contentLength = 0;
+    }
+
+    @Override
+    public void resetBuffer() {
+        if (isCommitted()) {
+            throw new IllegalStateException("Response already committed.");
+        }
+        bodySupport.reset();
+    }
+
+    @Override
+    public int getBufferSize() {
+        return this.bufferSize;
+    }
+
+    @Override
+    public void setBufferSize(int size) {
+        this.bufferSize = size;
+    }
+
+    @Override
+    public void flushBuffer() {
+        isCommitted = true;
+    }
+
+    @Override
+    public boolean isCommitted() {
+        return isCommitted;
+    }
+
+    public byte[] getOutput() {
+        return bodySupport.getOutput();
+    }
+
+    public String getOutputAsString() {
+        return bodySupport.getOutputAsString(getCharacterEncoding());
+    }
+
+    @Override
+    public void addCookie(Cookie cookie) {
+        cookieSupport.addCookie(cookie);
+    }
+
+    /**
+     * Get cookie
+     * @param name Cookie name
+     * @return Cookie or null
+     */
+    public Cookie getCookie(String name) {
+        return cookieSupport.getCookie(name);
+    }
+
+    /**
+     * Get cookies
+     * @return Cookies array or null if no cookie defined
+     */
+    public Cookie[] getCookies() {
+        return cookieSupport.getCookies();
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public Locale getLocale() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setLocale(Locale loc) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String encodeRedirectUrl(String url) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String encodeRedirectURL(String url) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String encodeUrl(String url) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String encodeURL(String url) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/servlet/ResponseBodySupport.java b/src/main/java/org/apache/sling/testing/mock/sling/servlet/ResponseBodySupport.java
new file mode 100644
index 0000000..128299b
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/servlet/ResponseBodySupport.java
@@ -0,0 +1,93 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.servlet;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+
+import javax.servlet.ServletOutputStream;
+
+/**
+ * Manage response body content.
+ */
+class ResponseBodySupport {
+
+    private ByteArrayOutputStream outputStream;
+    private ServletOutputStream servletOutputStream;
+    private PrintWriter printWriter;
+
+    public ResponseBodySupport() {
+        reset();
+    }
+
+    public void reset() {
+        outputStream = new ByteArrayOutputStream();
+        servletOutputStream = null;
+        printWriter = null;
+    }
+
+    public ServletOutputStream getOutputStream() {
+        if (servletOutputStream == null) {
+            servletOutputStream = new ServletOutputStream() {
+                @Override
+                public void write(int b) throws IOException {
+                    outputStream.write(b);
+                }
+            };
+        }
+        return servletOutputStream;
+    }
+
+    public PrintWriter getWriter(String charset) {
+        if (printWriter == null) {
+            try {
+                printWriter = new PrintWriter(new OutputStreamWriter(getOutputStream(), charset));
+            } catch (UnsupportedEncodingException ex) {
+                throw new RuntimeException("Unsupported encoding: " + charset, ex);
+            }
+        }
+        return printWriter;
+    }
+
+    public byte[] getOutput() {
+        if (servletOutputStream != null) {
+            try {
+                servletOutputStream.flush();
+            } catch (IOException ex) {
+                // ignore
+            }
+        }
+        return outputStream.toByteArray();
+    }
+
+    public String getOutputAsString(String charset) {
+        if (printWriter != null) {
+            printWriter.flush();
+        }
+        try {
+            return new String(getOutput(), charset);
+        } catch (UnsupportedEncodingException ex) {
+            throw new RuntimeException("Unsupported encoding: " + charset, ex);
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/servlet/package-info.java b/src/main/java/org/apache/sling/testing/mock/sling/servlet/package-info.java
new file mode 100644
index 0000000..389e6ec
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/servlet/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/**
+ * Mock implementation of selected Servlet-related Sling APIs.
+ */
+package org.apache.sling.testing.mock.sling.servlet;
+
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/spi/ResourceResolverTypeAdapter.java b/src/main/java/org/apache/sling/testing/mock/sling/spi/ResourceResolverTypeAdapter.java
new file mode 100644
index 0000000..cc20279
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/sling/spi/ResourceResolverTypeAdapter.java
@@ -0,0 +1,46 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.spi;
+
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.jcr.api.SlingRepository;
+
+/**
+ * SPI interface for resource resolver type implementations to provide a mock
+ * resource resolver factory.
+ */
+public interface ResourceResolverTypeAdapter {
+
+    /**
+     * Gets resource resolver factory instance. Can be null if only a
+     * SlingRepository is provided, in this case the method
+     * {@link #newSlingRepository()} has to return a value.
+     * @return Resource resolver factory instance or null
+     */
+    ResourceResolverFactory newResourceResolverFactory();
+
+    /**
+     * Get SlingRepository instance. Can be null if a resource resolver factory
+     * is provided, in this case the method
+     * {@link #newResourceResolverFactory()} has to return a value.
+     * @return Sling repository instance or null
+     */
+    SlingRepository newSlingRepository();
+
+}
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
new file mode 100644
index 0000000..407ab8b
--- /dev/null
+++ b/src/site/markdown/index.md
@@ -0,0 +1,67 @@
+## About Sling Mocks
+
+Mock implementation of selected Sling APIs.
+
+
+### Maven Dependency
+
+```xml
+<dependency>
+  <groupId>org.apache.sling</groupId>
+  <artifactId>org.apache.sling.testing.sling-mock</artifactId>
+  <version>1.0.0-SNAPHOT</version>
+</dependency>
+```
+
+### Documentation
+
+* [Sling Mocks Usage][usage-mocks]
+* [Content Loader Usage][usage-content-loader]
+* [API Documentation][apidocs]
+* [Changelog][changelog]
+
+
+### Implemented mock features
+
+The mock implementation supports:
+
+* `ResourceResolver` implementation for reading and writing resource data using the Sling Resource API
+    * Backed by a [mocked][jcr-mock] or real Jackrabbit JCR implementation
+    * Uses the productive [Sling JCR resource provider implementation][jcr-resource] internally to do the Resource-JCR mapping
+    * Alternatively the non-JCR mock implementation provided by the 
+   [Sling resourceresolver-mock implementation][resourceresolver-mock] can be used
+* `AdpaterManager` implementation for registering adapter factories and resolving adaptions
+    * The implementation is thread-safe so it can be used in parallel running unit tests
+* `SlingScriptHelper` implementation providing access to mocked request/response objects and supports getting
+   OSGi services from the [mocked OSGi][osgi-mock] environment.
+* Implementations of the servlet-related Sling API classes like `SlingHttpServletRequest` and `SlingHttpServletRequest`
+    * It is possible to set request data to simulate a certian Sling HTTP request
+* Additional services like `MockModelAdapterFactory` and  `MimeTypeService` 
+
+[osgi-mock]: http://sling.apache.org/testing/osgi-mock/
+[jcr-mock]: http://sling.apache.org/testing/jcr-mock/
+[jcr-resource]: http://svn.apache.org/repos/asf/sling/trunk/bundles/jcr/resource
+[resourceresolver-mock]: http://svn.eu.apache.org/repos/asf/sling/trunk/testing/resourceresolver-moc
+
+The following features are *not supported*:
+
+* It is not possible (nor intended) to really execute sling components/scripts and render their results.
+    * The goal is to test supporting classes in Sling context, not the sling components/scripts themselves
+
+See [Sling Mocks Usage][usage-mocks].
+
+
+### Additional features
+
+Additional features provided:
+
+* `ContentLoader` supports importing JSON data and binary data into the mock resource hierarchy to easily 
+  prepare a test fixture consisting of a hierarchy of resources and properties.
+    * The same JSON format can be used that is provided by the Sling GET servlet for output
+
+See [Content Loader Usage][usage-content-loader].
+
+[usage-mocks]: usage-mocks.html
+[usage-content-loader]: usage-content-loader.html
+[apidocs]: apidocs/
+[changelog]: changes-report.html
diff --git a/src/site/markdown/resource-resolver-types.md b/src/site/markdown/resource-resolver-types.md
new file mode 100644
index 0000000..3cacb49
--- /dev/null
+++ b/src/site/markdown/resource-resolver-types.md
@@ -0,0 +1,53 @@
+## Resource Resolver Types
+
+The Sling Mocks resource resolver implementation supports different "types" of adapters for the mocks.
+Depending on the type an underlying JCR repository is used or not, and the data ist stored in-memory or in a real 
+repository.
+
+This pages lists all resource resolver types currently supported.
+
+### RESOURCERESOLVER_MOCK (default)
+
+* Simulates an In-Memory resource tree, does not provide adaptions to JCR API.
+* Based on the [Sling resourceresolver-mock implementation][resourceresolver-mock] implementation
+* You can use it to make sure the code you want to test does not contain references to JCR API.
+* Behaves slightly different from JCR resource mapping e.g. handling binary and date values.
+* This resource resolver type is very fast because data is stored in memory and no JCR mapping is applied.
+
+### JCR_MOCK
+
+* Based on the [JCR Mocks][jcr-mock] implementation
+* Uses the productive [Sling JCR resource provider implementation][jcr-resource] internally to do the Resource-JCR mapping
+* Is quite fast because data is stored only in-memory
+
+### JCR_JACKRABBIT
+
+* Uses a real JCR Jackrabbit implementation (not Oak) as provided by [sling/commons/testing][sling-comons-testing]
+* Full JCR/Sling features supported e.g. observations manager, transactions, versioning
+* Uses the productive [Sling JCR resource provider implementation][jcr-resource] internally to do the Resource-JCR mapping
+* Takes some seconds for startup on the first access 
+* All node types that are used when reading/writing data have to be registered
+
+_Warnings/Remarks_
+
+* The repository is not cleared for each unit test, so make sure us use a unique node path for each unit test.
+* To import Sling content you have to fully register all node types required for the data
+* The [sling/commons/testing][sling-comons-testing] dependency introduces a lot of further dependencies from
+  jackrabbit and others, be careful that they do not conflict and are imported in the right order in your test project
+
+To use this type you have to declare an additional dependency in your test project:
+
+```xml
+<dependency>
+  <groupId>org.apache.sling</groupId>
+  <artifactId>org.apache.sling.testing.sling-mock-jackrabbit</artifactId>
+  <version>1.0.0-SNAPHOT</version>
+  <scope>test</scope>
+</dependency>
+```
+
+
+[jcr-mock]: http://sling.apache.org/testing/jcr-mock/
+[jcr-resource]: http://svn.apache.org/repos/asf/sling/trunk/bundles/jcr/resource
+[resourceresolver-mock]: http://svn.eu.apache.org/repos/asf/sling/trunk/testing/resourceresolver-moc
+[sling-comons-testing]: http://svn.apache.org/repos/asf/sling/trunk/bundles/commons/testing
diff --git a/src/site/markdown/usage-content-loader.md b/src/site/markdown/usage-content-loader.md
new file mode 100644
index 0000000..8d88146
--- /dev/null
+++ b/src/site/markdown/usage-content-loader.md
@@ -0,0 +1,59 @@
+## Usage
+
+### Import resource data from JSON file in classpath
+
+With the `ContentLoader` it is possible to import structured resource and property data from a JSON file stored
+in the classpath beneath the unit tests. This data can be used as text fixture for unit tests.
+
+Example JSON data:
+
+```json
+{
+  "jcr:primaryType": "app:Page",
+  "jcr:content": {
+    "jcr:primaryType": "app:PageContent",
+    "jcr:title": "English",
+    "app:template": "/apps/sample/templates/homepage",
+    "sling:resourceType": "sample/components/homepage",
+    "jcr:createdBy": "admin",
+    "jcr:created": "Thu Aug 07 2014 16:32:59 GMT+0200",
+    "par": {
+      "jcr:primaryType": "nt:unstructured",
+      "sling:resourceType": "foundation/components/parsys",
+      "colctrl": {
+        "jcr:primaryType": "nt:unstructured",
+        "layout": "2;colctrl-lt0",
+        "sling:resourceType": "foundation/components/parsys/colctrl"
+      }
+    }
+  }
+}
+```
+
+Example code to import the JSON data:
+
+```java
+ResourceResolver resolver = MockSling.newResourceResolver();
+ContentLoader contentLoader = new ContentLoader(resolver);
+contentLoader.json("/sample-data.json", "/content/sample/en");
+```
+
+This codes creates a new resource at `/content/sample/en` (and - if not existent - the parent resources) and
+imports the JSON data to this node. It can be accessed using the Sling Resource or JCR API afterwards.
+
+
+### Import binary data from file in classpath
+
+With the `ContentLoader` it is possible to import a binary file stored in the classpath beneath the unit tests.
+The data is stored usig a nt:file/nt:resource or nt:resource node type. 
+
+Example code to import a binary file:
+
+```java
+ResourceResolver resolver = MockSling.newResourceResolver();
+ContentLoader contentLoader = new ContentLoader(resolver);
+contentLoader.binaryFile("/sample-file.gif", "/content/binary/sample-file.gif");
+```
+
+This codes creates a new resource at `/content/binary/sample-file.gif` (and - if not existent - the parent 
+resources) and imports the binary data to a jcr:content subnode.
diff --git a/src/site/markdown/usage-mocks.md b/src/site/markdown/usage-mocks.md
new file mode 100644
index 0000000..a942c09
--- /dev/null
+++ b/src/site/markdown/usage-mocks.md
@@ -0,0 +1,130 @@
+## Usage
+
+The factory class `MockSling` allows to instantiate the different mock implementations.
+
+### Sling Resource Resolver
+
+Example:
+
+```java
+// get a resource resolver
+ResourceResolver resolver = MockSling.newResourceResolver();
+
+// get a resource resolver backed by a specific repository type
+ResourceResolver resolver = MockSling.newResourceResolver(ResourceResolverType.JCR_MOCK);
+```
+The following types are supported currently: [Resource Resolver Types](resource-resolver-types.html)
+
+### Adapter Factories
+
+You can register your own or existing adapter factories to support adaptions e.g. for classes extending `SlingAdaptable`.
+
+Example:
+
+```java
+// register adapter factory
+BundleContext bundleContext = MockOsgi.newBundleContext();
+MockSling.setAdapterManagerBundleContext(bundleContext);
+bundleContext.registerService(myAdapterFactory);
+
+// test adaption
+MyClass object = resource.adaptTo(MyClass.class);
+
+// cleanup after unit test
+MockSling.clearAdapterManagerBundleContext();
+```
+
+Make sure you clean up the adapter manager bundle association after running the unit test otherwise it can 
+interfere with the following tests. If you use the `SlingContext` Junit rule this is done automatically for you.
+
+
+### SlingScriptHelper
+
+Example:
+
+```java
+// get script helper
+SlingScriptHelper scriptHelper = MockSling.newSlingScriptHelper();
+
+// get request
+SlingHttpServletRequest request = scriptHelper.getRequest();
+
+// get service
+MyService object = scriptHelper.getService(MyService.class);
+```
+
+To support getting OSGi services you have to register them via the `BundleContext` interface of the
+[JCR Mocks][jcr-mock] before. You can use an alternative factory method for the `SlingScriptHelper` providing
+existing instances of request, response and bundle context. 
+
+
+### SlingHttpServletRequest
+
+Example for preparing a sling request with custom request data:
+
+```java
+// prepare sling request
+ResourceResolver resourceResolver = MockSling.newResourceResolver();
+MockSlingHttpServletRequest request = new MockSlingHttpServletRequest(resourceResolver);
+
+// simulate query string
+request.setQueryString("param1=aaa&param2=bbb");
+
+// alternative - set query parameters as map
+request.setParameterMap(ImmutableMap.<String,Object>builder()
+    .put("param1", "aaa")
+    .put("param2", "bbb")
+    .build());
+
+// set current resource
+request.setResource(resourceResolver.getResource("/content/sample"));
+
+// set sling request path info properties
+MockRequestPathInfo requestPathInfo = (MockRequestPathInfo)request.getRequestPathInfo();
+requestPathInfo.setSelectorString("selector1.selector2");
+requestPathInfo.setExtension("html");
+
+// set method
+request.setMethod(HttpConstants.METHOD_POST);
+
+// set attributes
+request.setAttribute("attr1", "value1");
+
+// set headers
+request.addHeader("header1", "value1");
+
+// set cookies
+request.addCookie(new Cookie("cookie1", "value1"));
+```
+
+### SlingHttpServletResponse
+
+Example for preparing a sling response which can collect the data that was written to it:
+
+```java
+// prepare sling response
+MockSlingHttpServletResponse response = new MockSlingHttpServletResponse();
+
+// execute your unit test code that writes to the response...
+
+// validate status code
+assertEquals(HttpServletResponse.SC_OK, response.getStatus());
+
+// validate content type and content length
+assertEquals("text/plain;charset=UTF-8", response.getContentType());
+assertEquals(CharEncoding.UTF_8, response.getCharacterEncoding());
+assertEquals(55, response.getContentLength());
+
+// validate headers
+assertTrue(response.containsHeader("header1"));
+assertEquals("5", response.getHeader("header2"));
+
+// validate response body as string
+assertEquals(TEST_CONTENT, response.getOutputAsString());
+
+// validate response body as binary data
+assertArrayEquals(TEST_DATA, response.getOutput());
+```
+
+
+[jcr-mock]: http://sling.apache.org/testing/jcr-mock/
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/MockAdapterManagerTest.java b/src/test/java/org/apache/sling/testing/mock/sling/MockAdapterManagerTest.java
new file mode 100644
index 0000000..6ca7a5a
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/MockAdapterManagerTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.apache.sling.api.adapter.AdapterFactory;
+import org.apache.sling.api.adapter.SlingAdaptable;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+public class MockAdapterManagerTest {
+
+    @Test
+    public void test() {
+        AdaptableTest sampleObject = new AdaptableTest();
+        assertNull(sampleObject.adaptTo(String.class));
+
+        BundleContext bundleContext = MockOsgi.newBundleContext();
+        MockSling.setAdapterManagerBundleContext(bundleContext);
+
+        bundleContext.registerService(AdapterFactory.class.getName(), new AdapterFactory() {
+            @SuppressWarnings("unchecked")
+            @Override
+            public <AdapterType> AdapterType getAdapter(final Object adaptable, final Class<AdapterType> type) {
+                if (adaptable instanceof AdaptableTest && type.isAssignableFrom(String.class)) {
+                    return (AdapterType) ((AdaptableTest) adaptable).toString();
+                }
+                return null;
+            }
+        }, null);
+
+        sampleObject = new AdaptableTest();
+        assertEquals("adaptedString", sampleObject.adaptTo(String.class));
+
+        MockSling.clearAdapterManagerBundleContext();
+
+        sampleObject = new AdaptableTest();
+        assertNull(sampleObject.adaptTo(String.class));
+    }
+
+    private static class AdaptableTest extends SlingAdaptable {
+
+        @Override
+        public String toString() {
+            return "adaptedString";
+        }
+
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/MockSlingRepositoryTest.java b/src/test/java/org/apache/sling/testing/mock/sling/MockSlingRepositoryTest.java
new file mode 100644
index 0000000..e1aa2e1
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/MockSlingRepositoryTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling;
+
+import static org.junit.Assert.assertNotNull;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.testing.mock.jcr.MockJcr;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MockSlingRepositoryTest {
+
+    private SlingRepository repository;
+
+    @Before
+    public void setUp() {
+        this.repository = new MockSlingRepository(MockJcr.newRepository());
+    }
+
+    @SuppressWarnings("deprecation")
+    @Test
+    public void testLogin() throws RepositoryException {
+        assertNotNull(this.repository.loginAdministrative(MockJcr.DEFAULT_WORKSPACE));
+        assertNotNull(this.repository.loginService("test", MockJcr.DEFAULT_WORKSPACE));
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/MockSlingScriptHelperTest.java b/src/test/java/org/apache/sling/testing/mock/sling/MockSlingScriptHelperTest.java
new file mode 100644
index 0000000..bde6899
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/MockSlingScriptHelperTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
+import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
+import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletResponse;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+public class MockSlingScriptHelperTest {
+
+    private ResourceResolver resourceResolver;
+    private SlingHttpServletRequest request;
+    private SlingHttpServletResponse response;
+    private BundleContext bundleContext;
+    private SlingScriptHelper scriptHelper;
+
+    @Before
+    public void setUp() throws Exception {
+        this.resourceResolver = MockSling.newResourceResolver();
+        this.request = new MockSlingHttpServletRequest(this.resourceResolver);
+        this.response = new MockSlingHttpServletResponse();
+        this.bundleContext = MockOsgi.newBundleContext();
+        this.scriptHelper = MockSling.newSlingScriptHelper(this.request, this.response, this.bundleContext);
+    }
+
+    @Test
+    public void testRequest() {
+        assertSame(this.request, this.scriptHelper.getRequest());
+    }
+
+    @Test
+    public void testResponse() {
+        assertSame(this.response, this.scriptHelper.getResponse());
+    }
+
+    @Test
+    public void testGetService() {
+        this.bundleContext.registerService(String.class.getName(), "test", null);
+        assertEquals("test", this.scriptHelper.getService(String.class));
+    }
+
+    @Test
+    public void testGetServices() {
+        Integer[] services = new Integer[] { 1, 2, 3 };
+        for (Integer service : services) {
+            this.bundleContext.registerService(Integer.class.getName(), service, null);
+        }
+        Integer[] servicesResult = this.scriptHelper.getServices(Integer.class, null);
+        assertArrayEquals(services, servicesResult);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/builder/ContentBuilderTest.java b/src/test/java/org/apache/sling/testing/mock/sling/builder/ContentBuilderTest.java
new file mode 100644
index 0000000..fc4ab4e
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/builder/ContentBuilderTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.builder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+public class ContentBuilderTest {
+
+    @Rule
+    public SlingContext context = new SlingContext(ResourceResolverType.RESOURCERESOLVER_MOCK);
+
+    @Test
+    public void testResource() {
+        Resource resource = context.create().resource("/content/test1/resource1");
+        assertNotNull(resource);
+        assertEquals("resource1", resource.getName());
+        assertTrue(ResourceUtil.getValueMap(resource).isEmpty());
+    }
+
+    @Test
+    public void testResourceWithProperties() {
+        Resource resource = context.create().resource(
+                "/content/test1/resource2",
+                ImmutableMap.<String, Object> builder().put("jcr:title", "Test Title").put("stringProp", "value1")
+                        .build());
+        assertNotNull(resource);
+        assertEquals("resource2", resource.getName());
+        ValueMap props = ResourceUtil.getValueMap(resource);
+        assertEquals("Test Title", props.get("jcr:title", String.class));
+        assertEquals("value1", props.get("stringProp", String.class));
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java b/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java
new file mode 100644
index 0000000..eed2ec6
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/context/SlingContextImplTest.java
@@ -0,0 +1,224 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.context;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.commons.mime.MimeTypeService;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.settings.SlingSettingsService;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.loader.ContentLoader;
+import org.apache.sling.testing.mock.sling.services.MockMimeTypeService;
+import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+public class SlingContextImplTest {
+
+    private SlingContextImpl context;
+
+    @Before
+    public void setUp() throws Exception {
+        this.context = new SlingContextImpl();
+        this.context.setResourceResolverType(ResourceResolverType.RESOURCERESOLVER_MOCK);
+        this.context.setUp();
+
+        ContentLoader contentLoader = this.context.load();
+        contentLoader.json("/json-import-samples/content.json", "/content/sample/en");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        this.context.tearDown();
+    }
+    
+    @Test
+    public void testContextObjects() {
+        assertNotNull(context.componentContext());
+        assertNotNull(context.bundleContext());
+        assertNotNull(context.resourceResolver());
+        assertNotNull(context.request());
+        assertNotNull(context.requestPathInfo());
+        assertNotNull(context.response());
+        assertNotNull(context.slingScriptHelper());
+    }
+
+    @Test
+    public void testSlingBindings() {
+        SlingBindings bindings = (SlingBindings) context.request().getAttribute(SlingBindings.class.getName());
+        assertNotNull(bindings);
+        assertSame(context.request(), bindings.get(SlingBindings.REQUEST));
+        assertSame(context.response(), bindings.get(SlingBindings.RESPONSE));
+        assertSame(context.slingScriptHelper(), bindings.get(SlingBindings.SLING));
+    }
+
+    @Test
+    public void testRegisterService() {
+        Set<String> myService = new HashSet<String>();
+        context.registerService(Set.class, myService);
+
+        Set<?> serviceResult = context.getService(Set.class);
+        assertSame(myService, serviceResult);
+    }
+
+    @Test
+    public void testRegisterServiceWithProperties() {
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("prop1", "value1");
+
+        Set<String> myService = new HashSet<String>();
+        context.registerService(Set.class, myService, props);
+
+        ServiceReference serviceReference = context.bundleContext().getServiceReference(Set.class.getName());
+        Object serviceResult = context.bundleContext().getService(serviceReference);
+        assertSame(myService, serviceResult);
+        assertEquals("value1", serviceReference.getProperty("prop1"));
+    }
+
+    @Test
+    public void testRegisterMultipleServices() {
+        Set<String> myService1 = new HashSet<String>();
+        context.registerService(Set.class, myService1);
+        Set<String> myService2 = new HashSet<String>();
+        context.registerService(Set.class, myService2);
+
+        Set[] serviceResults = context.getServices(Set.class, null);
+        assertSame(myService1, serviceResults[0]);
+        assertSame(myService2, serviceResults[1]);
+    }
+
+    @Test
+    public void testSetCurrentResource() {
+        context.currentResource("/content/sample/en/jcr:content/par/colctrl");
+        assertEquals("/content/sample/en/jcr:content/par/colctrl", context.currentResource().getPath());
+
+        context.currentResource(context.resourceResolver().getResource("/content/sample/en/jcr:content/par"));
+        assertEquals("/content/sample/en/jcr:content/par", context.currentResource().getPath());
+
+        context.currentResource((Resource) null);
+        assertNull(context.request().getResource());
+
+        context.currentResource((String) null);
+        assertNull(context.request().getResource());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testSetCurrentResourceNonExisting() {
+        context.currentResource("/non/existing");
+    }
+
+    @Test
+    public void testSlingModelsRequestAttribute() {
+        context.request().setAttribute("prop1", "myValue");
+        RequestAttributeModel model = context.request().adaptTo(RequestAttributeModel.class);
+        assertEquals("myValue", model.getProp1());
+    }
+
+    @Test
+    public void testSlingModelsOsgiService() {
+        context.registerService(new MockMimeTypeService());
+
+        ResourceResolver resolver = MockSling.newResourceResolver();
+        OsgiServiceModel model = resolver.adaptTo(OsgiServiceModel.class);
+        assertNotNull(model.getMimeTypeService());
+        assertEquals("text/html", model.getMimeTypeService().getMimeType("html"));
+    }
+
+    @Test
+    public void testSlingModelsInvalidAdapt() {
+        OsgiServiceModel model = context.request().adaptTo(OsgiServiceModel.class);
+        assertNull(model);
+    }
+
+    @Test
+    public void testAdaptToInterface() {
+        context.addModelsForPackage("org.apache.sling.testing.mock.sling.context");
+
+        MockSlingHttpServletRequest request = new MockSlingHttpServletRequest();
+        request.setAttribute("prop1", "myValue");
+        ServiceInterface model = request.adaptTo(ServiceInterface.class);
+        assertNotNull(model);
+        assertEquals("myValue", model.getPropValue());
+    }
+
+    @Test
+    public void testRegisterInjectActivate() {
+        context.registerInjectActivateService(new Object());
+    }
+
+    @Test
+    public void testRunModes() {
+        SlingSettingsService slingSettings = context.getService(SlingSettingsService.class);
+        assertEquals(SlingContextImpl.DEFAULT_RUN_MODES, slingSettings.getRunModes());
+
+        context.runMode("mode1", "mode2");
+        Set<String> newRunModes = slingSettings.getRunModes();
+        assertEquals(2, newRunModes.size());
+        assertTrue(newRunModes.contains("mode1"));
+        assertTrue(newRunModes.contains("mode2"));
+    }
+
+    @Model(adaptables = SlingHttpServletRequest.class)
+    public interface RequestAttributeModel {
+        @Inject
+        String getProp1();
+    }
+
+    @Model(adaptables = ResourceResolver.class)
+    public interface OsgiServiceModel {
+        @Inject
+        MimeTypeService getMimeTypeService();
+    }
+
+    public interface ServiceInterface {
+        String getPropValue();
+    }
+
+    @Model(adaptables = SlingHttpServletRequest.class, adapters = ServiceInterface.class)
+    public static class ServiceInterfaceImpl implements ServiceInterface {
+
+        @Inject
+        private String prop1;
+
+        @Override
+        public String getPropValue() {
+            return this.prop1;
+        }
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderBinaryTest.java b/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderBinaryTest.java
new file mode 100644
index 0000000..76c85c4
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderBinaryTest.java
@@ -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 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 org.apache.sling.testing.mock.sling.jcrmock.loader;
+
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.loader.AbstractContentLoaderBinaryTest;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ContentLoaderBinaryTest extends AbstractContentLoaderBinaryTest {
+
+    protected ResourceResolverType getResourceResolverType() {
+        return ResourceResolverType.JCR_MOCK;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderJsonDamTest.java b/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderJsonDamTest.java
new file mode 100644
index 0000000..ceb5b57
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderJsonDamTest.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 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 org.apache.sling.testing.mock.sling.jcrmock.loader;
+
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.loader.AbstractContentLoaderJsonDamTest;
+
+public class ContentLoaderJsonDamTest extends AbstractContentLoaderJsonDamTest {
+
+    protected ResourceResolverType getResourceResolverType() {
+        return ResourceResolverType.JCR_MOCK;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderJsonTest.java b/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderJsonTest.java
new file mode 100644
index 0000000..eaa297c
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/loader/ContentLoaderJsonTest.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 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 org.apache.sling.testing.mock.sling.jcrmock.loader;
+
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.loader.AbstractContentLoaderJsonTest;
+
+public class ContentLoaderJsonTest extends AbstractContentLoaderJsonTest {
+
+    protected ResourceResolverType getResourceResolverType() {
+        return ResourceResolverType.JCR_MOCK;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/resource/JcrResourceResolverTest.java b/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/resource/JcrResourceResolverTest.java
new file mode 100644
index 0000000..0e358f9
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/resource/JcrResourceResolverTest.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.jcrmock.resource;
+
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.resource.AbstractJcrResourceResolverTest;
+
+/**
+ * Implements simple write and read resource and values test. JCR API is used to
+ * create the test data.
+ */
+public class JcrResourceResolverTest extends AbstractJcrResourceResolverTest {
+
+    protected ResourceResolverType getResourceResolverType() {
+        return ResourceResolverType.JCR_MOCK;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/resource/SlingCrudResourceResolverTest.java b/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/resource/SlingCrudResourceResolverTest.java
new file mode 100644
index 0000000..005ab6c
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/resource/SlingCrudResourceResolverTest.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.jcrmock.resource;
+
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.resource.AbstractSlingCrudResourceResolverTest;
+
+/**
+ * Implements simple write and read resource and values test. Sling CRUD API is
+ * used to create the test data.
+ */
+public class SlingCrudResourceResolverTest extends AbstractSlingCrudResourceResolverTest {
+
+    protected ResourceResolverType getResourceResolverType() {
+        return ResourceResolverType.JCR_MOCK;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/junit/SlingContextTest.java b/src/test/java/org/apache/sling/testing/mock/sling/junit/SlingContextTest.java
new file mode 100644
index 0000000..24c72dd
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/junit/SlingContextTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.junit;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+
+import java.io.IOException;
+
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class SlingContextTest {
+
+    private final SlingContextCallback contextSetup = mock(SlingContextCallback.class);
+    private final SlingContextCallback contextTeardown = mock(SlingContextCallback.class);
+
+    // Run all unit tests for each resource resolver types listed here
+    @Rule
+    public SlingContext context = new SlingContext(contextSetup, contextTeardown,
+            ResourceResolverType.RESOURCERESOLVER_MOCK);
+
+    @Before
+    public void setUp() throws IOException, PersistenceException {
+        verify(contextSetup).execute(context);
+    }
+
+    @Test
+    public void testRequest() {
+        assertNotNull(context.request());
+    }
+
+    @After
+    public void tearDown() {
+        // reset required because mockito gets puzzled with the parameterized
+        // JUnit rule
+        // TODO: better solution?
+        reset(contextSetup);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderBinaryTest.java b/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderBinaryTest.java
new file mode 100644
index 0000000..5765612
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderBinaryTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.loader;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.commons.mime.MimeTypeService;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.BundleContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public abstract class AbstractContentLoaderBinaryTest {
+
+    private static final int SAMPLE_IMAGE_FILESIZE = 62;
+
+    private BundleContext bundleContext;
+    private ResourceResolver resourceResolver;
+    private ContentLoader contentLoader;
+
+    @Mock
+    private MimeTypeService mimeTypeService;
+
+    protected abstract ResourceResolverType getResourceResolverType();
+
+    protected ResourceResolver newResourceResolver() {
+        return MockSling.newResourceResolver(getResourceResolverType());
+    }
+
+    @Before
+    public final void setUp() {
+        bundleContext = MockOsgi.newBundleContext();
+        bundleContext.registerService(MimeTypeService.class.getName(), mimeTypeService, new Hashtable());
+        resourceResolver = newResourceResolver();
+        contentLoader = new ContentLoader(this.resourceResolver, this.bundleContext);
+
+        when(mimeTypeService.getMimeType("gif")).thenReturn("image/gif");
+    }
+
+    @Test
+    public void testBinaryFile() throws IOException {
+        contentLoader.binaryFile("/sample-image.gif", "/content/binary/sample-image.gif");
+
+        Resource fileResource = resourceResolver.getResource("/content/binary/sample-image.gif");
+        assertSampleImageFileSize(fileResource);
+        assertMimeType(fileResource.getChild(JcrConstants.JCR_CONTENT), "image/gif");
+    }
+
+    @Test
+    public void testBinaryFileWithMimeType() throws IOException {
+        contentLoader.binaryFile("/sample-image.gif", "/content/binary/sample-image.gif", "mime/test");
+
+        Resource fileResource = resourceResolver.getResource("/content/binary/sample-image.gif");
+        assertSampleImageFileSize(fileResource);
+        assertMimeType(fileResource.getChild(JcrConstants.JCR_CONTENT), "mime/test");
+    }
+
+    @Test
+    public void testBinaryResource() throws IOException {
+        contentLoader.binaryResource("/sample-image.gif", "/content/binary/sample-image.gif");
+
+        Resource fileResource = resourceResolver.getResource("/content/binary/sample-image.gif");
+        assertSampleImageFileSize(fileResource);
+        assertMimeType(fileResource, "image/gif");
+    }
+
+    @Test
+    public void testBinaryResourceWithMimeType() throws IOException {
+        contentLoader.binaryResource("/sample-image.gif", "/content/binary/sample-image.gif", "mime/test");
+
+        Resource fileResource = resourceResolver.getResource("/content/binary/sample-image.gif");
+        assertSampleImageFileSize(fileResource);
+        assertMimeType(fileResource, "mime/test");
+    }
+
+    private void assertSampleImageFileSize(Resource resource) throws IOException {
+        InputStream is = resource.adaptTo(InputStream.class);
+        assertNotNull("InputSteam is null for " + resource.getPath(), is);
+        byte[] binaryData = IOUtils.toByteArray(is);
+        assertEquals(SAMPLE_IMAGE_FILESIZE, binaryData.length);
+    }
+
+    private void assertMimeType(Resource resource, String mimeType) {
+        assertNotNull(resource);
+        assertEquals(mimeType, ResourceUtil.getValueMap(resource).get(JcrConstants.JCR_MIMETYPE, String.class));
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderJsonDamTest.java b/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderJsonDamTest.java
new file mode 100644
index 0000000..0f00113
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderJsonDamTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.loader;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.junit.Before;
+import org.junit.Test;
+
+public abstract class AbstractContentLoaderJsonDamTest {
+
+    private ResourceResolver resourceResolver;
+
+    protected abstract ResourceResolverType getResourceResolverType();
+
+    protected ResourceResolver newResourceResolver() {
+        ResourceResolver resolver = MockSling.newResourceResolver(getResourceResolverType());
+
+        if (getResourceResolverType() == ResourceResolverType.JCR_MOCK) {
+            try {
+                // dummy namespace registrations to make sure sling JCR resolver
+                // does not get mixed up with the prefixes
+                NamespaceRegistry namespaceRegistry = resolver.adaptTo(Session.class).getWorkspace()
+                        .getNamespaceRegistry();
+                namespaceRegistry.registerNamespace("sling", "http://mock/sling");
+                namespaceRegistry.registerNamespace("app", "http://mock/app");
+                namespaceRegistry.registerNamespace("dam", "http://mock/dam");
+            } catch (RepositoryException ex) {
+                throw new RuntimeException("Unable to register namespaces.", ex);
+            }
+        }
+
+        return resolver;
+    }
+
+    @Before
+    public final void setUp() {
+        this.resourceResolver = newResourceResolver();
+        ContentLoader contentLoader = new ContentLoader(this.resourceResolver);
+        contentLoader.json("/json-import-samples/dam.json", "/content/dam/sample");
+    }
+
+    @Test
+    public void testDamAssetMetadata() {
+        Resource assetMetadata = this.resourceResolver
+                .getResource("/content/dam/sample/portraits/scott_reynolds.jpg/jcr:content/metadata");
+        ValueMap props = ResourceUtil.getValueMap(assetMetadata);
+
+        assertEquals("Canon\u0000", props.get("tiff:Make", String.class));
+        assertEquals((Long) 807L, props.get("tiff:ImageWidth", Long.class));
+        assertEquals((Integer) 595, props.get("tiff:ImageLength", Integer.class));
+        assertEquals(4.64385986328125d, props.get("dam:ApertureValue", Double.class), 0.00000000001d);
+
+        assertArrayEquals(new String[] { "stockphotography:business/business_people", "properties:style/color",
+                "properties:orientation/landscape" }, props.get("app:tags", String[].class));
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderJsonTest.java b/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderJsonTest.java
new file mode 100644
index 0000000..778e968
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/loader/AbstractContentLoaderJsonTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.loader;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.junit.Before;
+import org.junit.Test;
+
+public abstract class AbstractContentLoaderJsonTest {
+
+    private ResourceResolver resourceResolver;
+
+    protected abstract ResourceResolverType getResourceResolverType();
+
+    protected ResourceResolver newResourceResolver() {
+        ResourceResolver resolver = MockSling.newResourceResolver(getResourceResolverType());
+
+        if (getResourceResolverType() == ResourceResolverType.JCR_MOCK) {
+            try {
+                // dummy namespace registrations to make sure sling JCR resolver
+                // does not get mixed up with the prefixes
+                NamespaceRegistry namespaceRegistry = resolver.adaptTo(Session.class).getWorkspace()
+                        .getNamespaceRegistry();
+                namespaceRegistry.registerNamespace("sling", "http://mock/sling");
+                namespaceRegistry.registerNamespace("app", "http://mock/app");
+                namespaceRegistry.registerNamespace("dam", "http://mock/dam");
+            } catch (RepositoryException ex) {
+                throw new RuntimeException("Unable to register namespaces.", ex);
+            }
+        }
+
+        return resolver;
+    }
+
+    @Before
+    public final void setUp() {
+        this.resourceResolver = newResourceResolver();
+        ContentLoader contentLoader = new ContentLoader(this.resourceResolver);
+        contentLoader.json("/json-import-samples/content.json", "/content/sample/en");
+    }
+
+    @Test
+    public void testPageResourceType() {
+        Resource resource = this.resourceResolver.getResource("/content/sample/en");
+        assertEquals("app:Page", resource.getResourceType());
+    }
+
+    @Test
+    public void testPageJcrPrimaryType() throws RepositoryException {
+        Resource resource = this.resourceResolver.getResource("/content/sample/en");
+        assertPrimaryNodeType(resource, "app:Page");
+    }
+
+    @Test
+    public void testPageContentResourceType() {
+        Resource resource = this.resourceResolver.getResource("/content/sample/en/toolbar/profiles/jcr:content");
+        assertEquals("sample/components/contentpage", resource.getResourceType());
+    }
+
+    @Test
+    public void testPageContentJcrPrimaryType() throws RepositoryException {
+        Resource resource = this.resourceResolver.getResource("/content/sample/en/toolbar/profiles/jcr:content");
+        assertPrimaryNodeType(resource, "app:PageContent");
+    }
+
+    @Test
+    public void testPageContentProperties() {
+        Resource resource = this.resourceResolver.getResource("/content/sample/en/toolbar/profiles/jcr:content");
+        ValueMap props = ResourceUtil.getValueMap(resource);
+        assertEquals(true, props.get("hideInNav", Boolean.class));
+
+        assertEquals((Long) 1234567890123L, props.get("longProp", Long.class));
+        assertEquals(1.2345d, props.get("decimalProp", Double.class), 0.00001d);
+        assertEquals(true, props.get("booleanProp", Boolean.class));
+
+        assertArrayEquals(new Long[] { 1234567890123L, 55L }, props.get("longPropMulti", Long[].class));
+        assertArrayEquals(new Double[] { 1.2345d, 1.1d }, props.get("decimalPropMulti", Double[].class));
+        assertArrayEquals(new Boolean[] { true, false }, props.get("booleanPropMulti", Boolean[].class));
+    }
+
+    @Test
+    public void testContentResourceType() {
+        Resource resource = this.resourceResolver.getResource("/content/sample/en/jcr:content/header");
+        assertEquals("sample/components/header", resource.getResourceType());
+    }
+
+    @Test
+    public void testContentJcrPrimaryType() throws RepositoryException {
+        Resource resource = this.resourceResolver.getResource("/content/sample/en/jcr:content/header");
+        assertPrimaryNodeType(resource, JcrConstants.NT_UNSTRUCTURED);
+    }
+
+    @Test
+    public void testContentProperties() {
+        Resource resource = this.resourceResolver.getResource("/content/sample/en/jcr:content/header");
+        ValueMap props = ResourceUtil.getValueMap(resource);
+        assertEquals("/content/dam/sample/header.png", props.get("imageReference", String.class));
+    }
+
+    private void assertPrimaryNodeType(final Resource resource, final String nodeType) throws RepositoryException {
+        Node node = resource.adaptTo(Node.class);
+        if (node != null) {
+            assertEquals(nodeType, node.getPrimaryNodeType().getName());
+        } else {
+            ValueMap props = ResourceUtil.getValueMap(resource);
+            assertEquals(nodeType, props.get(JcrConstants.JCR_PRIMARYTYPE));
+        }
+    }
+
+    @Test
+    public void testCalendarEcmaFormat() {
+        Resource resource = this.resourceResolver.getResource("/content/sample/en/jcr:content");
+        ValueMap props = ResourceUtil.getValueMap(resource);
+
+        Calendar calendar = props.get("app:lastModified", Calendar.class);
+        assertNotNull(calendar);
+
+        calendar.setTimeZone(TimeZone.getTimeZone("GMT+2"));
+
+        assertEquals(2014, calendar.get(Calendar.YEAR));
+        assertEquals(4, calendar.get(Calendar.MONTH) + 1);
+        assertEquals(22, calendar.get(Calendar.DAY_OF_MONTH));
+
+        assertEquals(15, calendar.get(Calendar.HOUR_OF_DAY));
+        assertEquals(11, calendar.get(Calendar.MINUTE));
+        assertEquals(24, calendar.get(Calendar.SECOND));
+    }
+    
+    @Test
+    public void testCalendarISO8601Format() {
+        Resource resource = this.resourceResolver.getResource("/content/sample/en/jcr:content");
+        ValueMap props = ResourceUtil.getValueMap(resource);
+
+        Calendar calendar = props.get("dateISO8601String", Calendar.class);
+        assertNotNull(calendar);
+
+        calendar.setTimeZone(TimeZone.getTimeZone("GMT+2"));
+        
+        assertEquals(2014, calendar.get(Calendar.YEAR));
+        assertEquals(4, calendar.get(Calendar.MONTH) + 1);
+        assertEquals(22, calendar.get(Calendar.DAY_OF_MONTH));
+
+        assertEquals(15, calendar.get(Calendar.HOUR_OF_DAY));
+        assertEquals(11, calendar.get(Calendar.MINUTE));
+        assertEquals(24, calendar.get(Calendar.SECOND));
+    }
+    
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractJcrResourceResolverTest.java b/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractJcrResourceResolverTest.java
new file mode 100644
index 0000000..f17f6d6
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractJcrResourceResolverTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.resource;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.time.DateUtils;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Implements simple write and read resource and values test.
+ * JCR API is used to create the test data.
+ */
+public abstract class AbstractJcrResourceResolverTest {
+
+    private static final String STRING_VALUE = "value1";
+    private static final String[] STRING_ARRAY_VALUE = new String[] { "value1", "value2" };
+    private static final int INTEGER_VALUE = 25;
+    private static final double DOUBLE_VALUE = 3.555d;
+    private static final boolean BOOLEAN_VALUE = true;
+    private static final Date DATE_VALUE = new Date(10000);
+    private static final Calendar CALENDAR_VALUE = Calendar.getInstance();
+    private static final byte[] BINARY_VALUE = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+
+    private ResourceResolver resourceResolver;
+    private Session session;
+    protected Node testRoot;
+    private static volatile long rootNodeCounter;
+
+    protected abstract ResourceResolverType getResourceResolverType();
+
+    protected ResourceResolver newResourceResolver() {
+        return MockSling.newResourceResolver(getResourceResolverType());
+    }
+
+    @Before
+    public final void setUp() throws RepositoryException {
+        resourceResolver = newResourceResolver();
+        session = resourceResolver.adaptTo(Session.class);
+
+        // prepare some test data using JCR API
+        Node rootNode = getTestRootNode();
+        Node node1 = rootNode.addNode("node1", JcrConstants.NT_UNSTRUCTURED);
+
+        node1.setProperty("stringProp", STRING_VALUE);
+        node1.setProperty("stringArrayProp", STRING_ARRAY_VALUE);
+        node1.setProperty("integerProp", INTEGER_VALUE);
+        node1.setProperty("doubleProp", DOUBLE_VALUE);
+        node1.setProperty("booleanProp", BOOLEAN_VALUE);
+        node1.setProperty("dateProp", DateUtils.toCalendar(DATE_VALUE));
+        node1.setProperty("calendarProp", CALENDAR_VALUE);
+        node1.setProperty("binaryProp", session.getValueFactory().createBinary(new ByteArrayInputStream(BINARY_VALUE)));
+
+        node1.addNode("node11", JcrConstants.NT_UNSTRUCTURED);
+        node1.addNode("node12", JcrConstants.NT_UNSTRUCTURED);
+
+        session.save();
+    }
+
+    @After
+    public final void tearDown() {
+        testRoot = null;
+    }
+
+    /**
+     * Return a test root node, created on demand, with a unique path
+     */
+    private Node getTestRootNode() throws RepositoryException {
+        if (testRoot == null) {
+            final Node root = session.getRootNode();
+            if (getResourceResolverType() == ResourceResolverType.JCR_JACKRABBIT) {
+                final Node classRoot = root.addNode(getClass().getSimpleName());
+                testRoot = classRoot.addNode(System.currentTimeMillis() + "_" + (rootNodeCounter++));
+            } else {
+                testRoot = root.addNode("test", JcrConstants.NT_UNSTRUCTURED);
+            }
+        }
+        return testRoot;
+    }
+
+    @Test
+    public void testGetResourcesAndValues() throws IOException, RepositoryException {
+        Resource resource1 = resourceResolver.getResource(getTestRootNode().getPath() + "/node1");
+        assertNotNull(resource1);
+        assertEquals("node1", resource1.getName());
+
+        ValueMap props = ResourceUtil.getValueMap(resource1);
+        assertEquals(STRING_VALUE, props.get("stringProp", String.class));
+        assertArrayEquals(STRING_ARRAY_VALUE, props.get("stringArrayProp", String[].class));
+        assertEquals((Integer) INTEGER_VALUE, props.get("integerProp", Integer.class));
+        assertEquals(DOUBLE_VALUE, props.get("doubleProp", Double.class), 0.0001);
+        assertEquals(BOOLEAN_VALUE, props.get("booleanProp", Boolean.class));
+        assertEquals(DATE_VALUE, props.get("dateProp", Date.class));
+        assertEquals(CALENDAR_VALUE.getTime(), props.get("calendarProp", Calendar.class).getTime());
+
+        Resource binaryPropResource = resource1.getChild("binaryProp");
+        InputStream is = binaryPropResource.adaptTo(InputStream.class);
+        byte[] dataFromResource = IOUtils.toByteArray(is);
+        is.close();
+        assertArrayEquals(BINARY_VALUE, dataFromResource);
+
+        // read second time to ensure not the original input stream was returned
+        InputStream is2 = binaryPropResource.adaptTo(InputStream.class);
+        byte[] dataFromResource2 = IOUtils.toByteArray(is2);
+        is2.close();
+        assertArrayEquals(BINARY_VALUE, dataFromResource2);
+
+        List<Resource> children = ImmutableList.copyOf(resource1.listChildren());
+        assertEquals(2, children.size());
+        assertEquals("node11", children.get(0).getName());
+        assertEquals("node12", children.get(1).getName());
+    }
+
+    @Test
+    public void testCreateNodeType() throws RepositoryException, PersistenceException {
+        Resource parent = resourceResolver.getResource(getTestRootNode().getPath());
+
+        Resource child = resourceResolver.create(parent, "nodeTypeResource", ImmutableMap.<String, Object> builder()
+                .put("sling:resourceType", JcrConstants.NT_UNSTRUCTURED).build());
+        assertNotNull(child);
+        assertEquals(JcrConstants.NT_UNSTRUCTURED, child.getResourceType());
+        assertEquals(JcrConstants.NT_UNSTRUCTURED, child.adaptTo(Node.class).getPrimaryNodeType().getName());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractSlingCrudResourceResolverTest.java b/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractSlingCrudResourceResolverTest.java
new file mode 100644
index 0000000..20ed560
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractSlingCrudResourceResolverTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.resource;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Implements simple write and read resource and values test. Sling CRUD API is
+ * used to create the test data.
+ */
+public abstract class AbstractSlingCrudResourceResolverTest {
+
+    private static final String STRING_VALUE = "value1";
+    private static final String[] STRING_ARRAY_VALUE = new String[] { "value1", "value2" };
+    private static final int INTEGER_VALUE = 25;
+    private static final double DOUBLE_VALUE = 3.555d;
+    private static final boolean BOOLEAN_VALUE = true;
+    private static final Date DATE_VALUE = new Date(10000);
+    private static final Calendar CALENDAR_VALUE = Calendar.getInstance();
+    private static final byte[] BINARY_VALUE = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+
+    private ResourceResolver resourceResolver;
+    protected Resource testRoot;
+    private static volatile long rootNodeCounter;
+
+    protected abstract ResourceResolverType getResourceResolverType();
+
+    protected ResourceResolver newResourceResolver() {
+        return MockSling.newResourceResolver(getResourceResolverType());
+    }
+
+    @Before
+    public final void setUp() throws IOException {
+        this.resourceResolver = newResourceResolver();
+
+        // prepare some test data using Sling CRUD API
+        Resource rootNode = getTestRootResource();
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
+        props.put("stringProp", STRING_VALUE);
+        props.put("stringArrayProp", STRING_ARRAY_VALUE);
+        props.put("integerProp", INTEGER_VALUE);
+        props.put("doubleProp", DOUBLE_VALUE);
+        props.put("booleanProp", BOOLEAN_VALUE);
+        props.put("dateProp", DATE_VALUE);
+        props.put("calendarProp", CALENDAR_VALUE);
+        props.put("binaryProp", new ByteArrayInputStream(BINARY_VALUE));
+        Resource node1 = this.resourceResolver.create(rootNode, "node1", props);
+
+        this.resourceResolver.create(node1, "node11", ValueMap.EMPTY);
+        this.resourceResolver.create(node1, "node12", ValueMap.EMPTY);
+
+        this.resourceResolver.commit();
+    }
+
+    @After
+    public final void tearDown() {
+        this.testRoot = null;
+    }
+
+    /**
+     * Return a test root resource, created on demand, with a unique path
+     * @throws PersistenceException
+     */
+    private Resource getTestRootResource() throws PersistenceException {
+        if (this.testRoot == null) {
+            Map<String, Object> props = new HashMap<String, Object>();
+            props.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
+            final Resource root = this.resourceResolver.getResource("/");
+            if (getResourceResolverType() == ResourceResolverType.JCR_JACKRABBIT) {
+                final Resource classRoot = this.resourceResolver.create(root, getClass().getSimpleName(), props);
+                this.testRoot = this.resourceResolver.create(classRoot, System.currentTimeMillis() + "_"
+                        + (rootNodeCounter++), props);
+            } else {
+                this.testRoot = this.resourceResolver.create(root, "test", props);
+            }
+        }
+        return this.testRoot;
+    }
+
+    @Test
+    public void testSimpleProperties() throws IOException {
+        Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1");
+        assertNotNull(resource1);
+        assertEquals("node1", resource1.getName());
+
+        ValueMap props = ResourceUtil.getValueMap(resource1);
+        assertEquals(STRING_VALUE, props.get("stringProp", String.class));
+        assertArrayEquals(STRING_ARRAY_VALUE, props.get("stringArrayProp", String[].class));
+        assertEquals((Integer) INTEGER_VALUE, props.get("integerProp", Integer.class));
+        assertEquals(DOUBLE_VALUE, props.get("doubleProp", Double.class), 0.0001);
+        assertEquals(BOOLEAN_VALUE, props.get("booleanProp", Boolean.class));
+    }
+
+    @Test
+    public void testDateProperty() throws IOException {
+        Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1");
+        ValueMap props = ResourceUtil.getValueMap(resource1);
+        // TODO: enable this test when JCR resource implementation supports
+        // writing Date objects (SLING-3846)
+        if (getResourceResolverType() != ResourceResolverType.JCR_MOCK
+                && getResourceResolverType() != ResourceResolverType.JCR_JACKRABBIT) {
+            assertEquals(DATE_VALUE, props.get("dateProp", Date.class));
+        }
+    }
+
+    @Test
+    public void testDatePropertyToCalendar() throws IOException {
+        Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1");
+        ValueMap props = ResourceUtil.getValueMap(resource1);
+        // TODO: enable this test when JCR resource implementation supports
+        // writing Date objects (SLING-3846)
+        if (getResourceResolverType() != ResourceResolverType.JCR_MOCK
+                && getResourceResolverType() != ResourceResolverType.JCR_JACKRABBIT) {
+            Calendar calendarValue = props.get("dateProp", Calendar.class);
+            assertNotNull(calendarValue);
+            assertEquals(DATE_VALUE, calendarValue.getTime());
+        }
+    }
+
+    @Test
+    public void testCalendarProperty() throws IOException {
+        Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1");
+        ValueMap props = ResourceUtil.getValueMap(resource1);
+        assertEquals(CALENDAR_VALUE.getTime(), props.get("calendarProp", Calendar.class).getTime());
+    }
+
+    @Test
+    public void testCalendarPropertyToDate() throws IOException {
+        Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1");
+        ValueMap props = ResourceUtil.getValueMap(resource1);
+        Date dateValue = props.get("calendarProp", Date.class);
+        assertNotNull(dateValue);
+        assertEquals(CALENDAR_VALUE.getTime(), dateValue);
+    }
+
+    @Test
+    public void testListChildren() throws IOException {
+        Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1");
+
+        List<Resource> children = ImmutableList.copyOf(resource1.listChildren());
+        assertEquals(2, children.size());
+        assertEquals("node11", children.get(0).getName());
+        assertEquals("node12", children.get(1).getName());
+    }
+
+    @Test
+    public void testBinaryData() throws IOException {
+        Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1");
+
+        Resource binaryPropResource = resource1.getChild("binaryProp");
+        InputStream is = binaryPropResource.adaptTo(InputStream.class);
+        byte[] dataFromResource = IOUtils.toByteArray(is);
+        is.close();
+        assertArrayEquals(BINARY_VALUE, dataFromResource);
+
+        // read second time to ensure not the original input stream was returned
+        // and this time using another syntax
+        InputStream is2 = ResourceUtil.getValueMap(resource1).get("binaryProp", InputStream.class);
+        byte[] dataFromResource2 = IOUtils.toByteArray(is2);
+        is2.close();
+        assertArrayEquals(BINARY_VALUE, dataFromResource2);
+    }
+
+    @Test
+    public void testPrimaryTypeResourceType() throws PersistenceException {
+        Resource resource = this.resourceResolver.getResource(getTestRootResource().getPath());
+        assertEquals(JcrConstants.NT_UNSTRUCTURED, resource.getResourceType());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/rrmock/loader/ContentLoaderBinaryTest.java b/src/test/java/org/apache/sling/testing/mock/sling/rrmock/loader/ContentLoaderBinaryTest.java
new file mode 100644
index 0000000..4d5eebf
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/rrmock/loader/ContentLoaderBinaryTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.rrmock.loader;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.loader.AbstractContentLoaderBinaryTest;
+
+public class ContentLoaderBinaryTest extends AbstractContentLoaderBinaryTest {
+
+    @Override
+    protected ResourceResolverType getResourceResolverType() {
+        return ResourceResolverType.RESOURCERESOLVER_MOCK;
+    }
+
+    @Override
+    protected ResourceResolver newResourceResolver() {
+        return MockSling.newResourceResolver(getResourceResolverType());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/rrmock/loader/ContentLoaderJsonDamTest.java b/src/test/java/org/apache/sling/testing/mock/sling/rrmock/loader/ContentLoaderJsonDamTest.java
new file mode 100644
index 0000000..4f6678d
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/rrmock/loader/ContentLoaderJsonDamTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.rrmock.loader;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.loader.AbstractContentLoaderJsonDamTest;
+
+public class ContentLoaderJsonDamTest extends AbstractContentLoaderJsonDamTest {
+
+    @Override
+    protected ResourceResolverType getResourceResolverType() {
+        return ResourceResolverType.RESOURCERESOLVER_MOCK;
+    }
+
+    @Override
+    protected ResourceResolver newResourceResolver() {
+        return MockSling.newResourceResolver(getResourceResolverType());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/rrmock/loader/ContentLoaderJsonTest.java b/src/test/java/org/apache/sling/testing/mock/sling/rrmock/loader/ContentLoaderJsonTest.java
new file mode 100644
index 0000000..0c33fd5
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/rrmock/loader/ContentLoaderJsonTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.rrmock.loader;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.loader.AbstractContentLoaderJsonTest;
+
+public class ContentLoaderJsonTest extends AbstractContentLoaderJsonTest {
+
+    @Override
+    protected ResourceResolverType getResourceResolverType() {
+        return ResourceResolverType.RESOURCERESOLVER_MOCK;
+    }
+
+    @Override
+    protected ResourceResolver newResourceResolver() {
+        return MockSling.newResourceResolver(getResourceResolverType());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/SlingCrudResourceResolverTest.java b/src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/SlingCrudResourceResolverTest.java
new file mode 100644
index 0000000..5bca11e
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/SlingCrudResourceResolverTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.rrmock.resource;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.resource.AbstractSlingCrudResourceResolverTest;
+
+public class SlingCrudResourceResolverTest extends AbstractSlingCrudResourceResolverTest {
+
+    @Override
+    protected ResourceResolverType getResourceResolverType() {
+        return ResourceResolverType.RESOURCERESOLVER_MOCK;
+    }
+
+    @Override
+    protected ResourceResolver newResourceResolver() {
+        return MockSling.newResourceResolver(getResourceResolverType());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/services/MockMimeTypeServiceTest.java b/src/test/java/org/apache/sling/testing/mock/sling/services/MockMimeTypeServiceTest.java
new file mode 100644
index 0000000..edd5b14
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/services/MockMimeTypeServiceTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.services;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.sling.commons.mime.MimeTypeService;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MockMimeTypeServiceTest {
+
+    private MimeTypeService mimeTypeService;
+
+    @Before
+    public void setUp() throws Exception {
+        this.mimeTypeService = new MockMimeTypeService();
+    }
+
+    @Test
+    public void testGetMimeType() {
+        assertEquals("text/html", this.mimeTypeService.getMimeType("html"));
+        assertEquals("application/json", this.mimeTypeService.getMimeType("json"));
+        assertEquals("image/jpeg", this.mimeTypeService.getMimeType("jpg"));
+        assertEquals("image/jpeg", this.mimeTypeService.getMimeType("jpeg"));
+    }
+
+    @Test
+    public void testGetExtension() {
+        assertEquals("html", this.mimeTypeService.getExtension("text/html"));
+        assertEquals("json", this.mimeTypeService.getExtension("application/json"));
+        assertEquals("jpeg", this.mimeTypeService.getExtension("image/jpeg"));
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/services/MockModelAdapterFactoryTest.java b/src/test/java/org/apache/sling/testing/mock/sling/services/MockModelAdapterFactoryTest.java
new file mode 100644
index 0000000..a4138c3
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/services/MockModelAdapterFactoryTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.services;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.adapter.AdapterFactory;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.commons.mime.MimeTypeService;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.impl.FirstImplementationPicker;
+import org.apache.sling.models.impl.injectors.OSGiServiceInjector;
+import org.apache.sling.models.impl.injectors.RequestAttributeInjector;
+import org.apache.sling.models.spi.ImplementationPicker;
+import org.apache.sling.models.spi.Injector;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+
+public class MockModelAdapterFactoryTest {
+
+    private ComponentContext componentContext;
+    private BundleContext bundleContext;
+
+    @Before
+    public void setUp() throws Exception {
+        componentContext = MockOsgi.newComponentContext();
+        bundleContext = componentContext.getBundleContext();
+        MockSling.setAdapterManagerBundleContext(bundleContext);
+
+        // register sling models adapter factory
+        MockModelAdapterFactory mockModelAdapterFactory = new MockModelAdapterFactory(componentContext);
+        bundleContext.registerService(AdapterFactory.class.getName(), mockModelAdapterFactory, null);
+
+        // register some injectors
+        bundleContext.registerService(Injector.class.getName(), new RequestAttributeInjector(), null);
+        OSGiServiceInjector osgiServiceInjector = new OSGiServiceInjector();
+        osgiServiceInjector.activate(componentContext);
+        bundleContext.registerService(Injector.class.getName(), osgiServiceInjector, null);
+
+        // register implementation pickers
+        bundleContext.registerService(ImplementationPicker.class.getName(), new FirstImplementationPicker(), null);
+
+        // scan for @Model classes
+        mockModelAdapterFactory.addModelsForPackage("org.apache.sling.testing.mock.sling.services");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        MockSling.clearAdapterManagerBundleContext();
+    }
+
+    @Test
+    public void testRequestAttribute() {
+        MockSlingHttpServletRequest request = new MockSlingHttpServletRequest();
+        request.setAttribute("prop1", "myValue");
+        RequestAttributeModel model = request.adaptTo(RequestAttributeModel.class);
+        assertNotNull(model);
+        assertEquals("myValue", model.getProp1());
+    }
+
+    @Test
+    public void testOsgiService() {
+        bundleContext.registerService(MimeTypeService.class.getName(), new MockMimeTypeService(), null);
+
+        ResourceResolver resolver = MockSling.newResourceResolver();
+        OsgiServiceModel model = resolver.adaptTo(OsgiServiceModel.class);
+        assertNotNull(model);
+        assertNotNull(model.getMimeTypeService());
+        assertEquals("text/html", model.getMimeTypeService().getMimeType("html"));
+    }
+
+    @Test
+    public void testInvalidAdapt() {
+        MockSlingHttpServletRequest request = new MockSlingHttpServletRequest();
+        OsgiServiceModel model = request.adaptTo(OsgiServiceModel.class);
+        assertNull(model);
+    }
+
+    @Test
+    public void testAdaptToInterface() {
+        MockSlingHttpServletRequest request = new MockSlingHttpServletRequest();
+        request.setAttribute("prop1", "myValue");
+        ServiceInterface model = request.adaptTo(ServiceInterface.class);
+        assertNotNull(model);
+        assertEquals("myValue", model.getPropValue());
+    }
+
+    @Model(adaptables = SlingHttpServletRequest.class)
+    public interface RequestAttributeModel {
+        @Inject
+        String getProp1();
+    }
+
+    @Model(adaptables = ResourceResolver.class)
+    public interface OsgiServiceModel {
+        @Inject
+        MimeTypeService getMimeTypeService();
+    }
+
+    public interface ServiceInterface {
+        String getPropValue();
+    }
+
+    @Model(adaptables = SlingHttpServletRequest.class, adapters = ServiceInterface.class)
+    public static class ServiceInterfaceImpl implements ServiceInterface {
+        @Inject
+        private String prop1;
+
+        @Override
+        public String getPropValue() {
+            return this.prop1;
+        }
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/services/MockSlingSettingServiceTest.java b/src/test/java/org/apache/sling/testing/mock/sling/services/MockSlingSettingServiceTest.java
new file mode 100644
index 0000000..10f0088
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/services/MockSlingSettingServiceTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.services;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+public class MockSlingSettingServiceTest {
+
+    @Test
+    public void testDefaultRunModes() {
+        Set<String> defaultRunModes = ImmutableSet.<String> builder().add("mode0").build();
+        MockSlingSettingService underTest = new MockSlingSettingService(defaultRunModes);
+        assertEquals(defaultRunModes, underTest.getRunModes());
+
+        Set<String> newRunModes = ImmutableSet.<String> builder().add("mode1").add("mode2").build();
+        underTest.setRunModes(newRunModes);
+        assertEquals(newRunModes, underTest.getRunModes());
+    }
+
+    @Test
+    public void testNoDefaultRunModes() {
+        MockSlingSettingService underTest = new MockSlingSettingService();
+        assertTrue(underTest.getRunModes().isEmpty());
+
+        Set<String> newRunModes = ImmutableSet.<String> builder().add("mode1").add("mode2").build();
+        underTest.setRunModes(newRunModes);
+        assertEquals(newRunModes, underTest.getRunModes());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockHttpSessionTest.java b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockHttpSessionTest.java
new file mode 100644
index 0000000..85e0612
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockHttpSessionTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.servlet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.servlet.http.HttpSession;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class MockHttpSessionTest {
+
+    private HttpSession httpSession;
+
+    @Before
+    public void setUp() throws Exception {
+        this.httpSession = new MockHttpSession();
+    }
+
+    @Test
+    public void testServletContext() {
+        assertNotNull(this.httpSession.getServletContext());
+    }
+
+    @Test
+    public void testId() {
+        assertNotNull(this.httpSession.getId());
+    }
+
+    @Test
+    public void testCreationTime() {
+        assertNotNull(this.httpSession.getCreationTime());
+    }
+
+    @Test
+    public void testAttributes() {
+        this.httpSession.setAttribute("attr1", "value1");
+        assertTrue(this.httpSession.getAttributeNames().hasMoreElements());
+        assertEquals("value1", this.httpSession.getAttribute("attr1"));
+        this.httpSession.removeAttribute("attr1");
+        assertFalse(this.httpSession.getAttributeNames().hasMoreElements());
+    }
+
+    @SuppressWarnings("deprecation")
+    @Test
+    public void testValues() {
+        this.httpSession.putValue("attr1", "value1");
+        assertEquals(1, this.httpSession.getValueNames().length);
+        assertEquals("value1", this.httpSession.getValue("attr1"));
+        this.httpSession.removeValue("attr1");
+        assertEquals(0, this.httpSession.getValueNames().length);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockRequestPathInfoTest.java b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockRequestPathInfoTest.java
new file mode 100644
index 0000000..006a415
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockRequestPathInfoTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.servlet;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class MockRequestPathInfoTest {
+
+    private MockRequestPathInfo requestPathInfo;
+
+    @Before
+    public void setUp() throws Exception {
+        this.requestPathInfo = new MockRequestPathInfo();
+    }
+
+    @Test
+    public void testExtension() {
+        assertNull(this.requestPathInfo.getExtension());
+        this.requestPathInfo.setExtension("ext");
+        assertEquals("ext", this.requestPathInfo.getExtension());
+    }
+
+    @Test
+    public void testResourcePath() {
+        assertNull(this.requestPathInfo.getResourcePath());
+        this.requestPathInfo.setResourcePath("/path");
+        assertEquals("/path", this.requestPathInfo.getResourcePath());
+    }
+
+    @Test
+    public void testSelector() {
+        assertNull(this.requestPathInfo.getSelectorString());
+        assertEquals(0, this.requestPathInfo.getSelectors().length);
+        this.requestPathInfo.setSelectorString("aa.bb");
+        assertEquals("aa.bb", this.requestPathInfo.getSelectorString());
+        assertEquals(2, this.requestPathInfo.getSelectors().length);
+        assertArrayEquals(new String[] { "aa", "bb" }, this.requestPathInfo.getSelectors());
+    }
+
+    @Test
+    public void testSuffix() {
+        assertNull(this.requestPathInfo.getSuffix());
+        this.requestPathInfo.setSuffix("/suffix");
+        assertEquals("/suffix", this.requestPathInfo.getSuffix());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockServletContextTest.java b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockServletContextTest.java
new file mode 100644
index 0000000..4c7b116
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockServletContextTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.servlet;
+
+import static org.junit.Assert.assertEquals;
+
+import javax.servlet.ServletContext;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class MockServletContextTest {
+
+    private ServletContext servletContext;
+
+    @Before
+    public void setUp() throws Exception {
+        this.servletContext = new MockServletContext();
+    }
+
+    @Test
+    public void testGetMimeType() {
+        assertEquals("application/octet-stream", this.servletContext.getMimeType("any"));
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequestTest.java b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequestTest.java
new file mode 100644
index 0000000..7539d09
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequestTest.java
@@ -0,0 +1,216 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.servlet;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.Calendar;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.servlets.HttpConstants;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MockSlingHttpServletRequestTest {
+
+    @Mock
+    private ResourceResolver resourceResolver;
+    @Mock
+    private Resource resource;
+
+    private MockSlingHttpServletRequest request;
+
+    @Before
+    public void setUp() throws Exception {
+        request = new MockSlingHttpServletRequest(resourceResolver);
+    }
+
+    @Test
+    public void testResourceResolver() {
+        assertSame(resourceResolver, request.getResourceResolver());
+    }
+
+    @Test
+    public void testDefaultResourceResolver() {
+        assertNotNull(new MockSlingHttpServletRequest().getResourceResolver());
+    }
+
+    @Test
+    public void testSession() {
+        HttpSession session = request.getSession(false);
+        assertNull(session);
+        session = request.getSession();
+        assertNotNull(session);
+    }
+
+    @Test
+    public void testRequestPathInfo() {
+        assertNotNull(request.getRequestPathInfo());
+    }
+
+    @Test
+    public void testAttributes() {
+        request.setAttribute("attr1", "value1");
+        assertTrue(request.getAttributeNames().hasMoreElements());
+        assertEquals("value1", request.getAttribute("attr1"));
+        request.removeAttribute("attr1");
+        assertFalse(request.getAttributeNames().hasMoreElements());
+    }
+
+    @Test
+    public void testResource() {
+        assertNull(request.getResource());
+        request.setResource(resource);
+        assertSame(resource, request.getResource());
+    }
+
+    @Test
+    public void testContextPath() {
+        assertNull(request.getContextPath());
+        request.setContextPath("/ctx");
+        assertEquals("/ctx", request.getContextPath());
+    }
+
+    @Test
+    public void testLocale() {
+        assertEquals(Locale.US, request.getLocale());
+    }
+
+    @Test
+    public void testQueryString() throws UnsupportedEncodingException {
+        assertNull(request.getQueryString());
+        assertEquals(0, request.getParameterMap().size());
+        assertFalse(request.getParameterNames().hasMoreElements());
+
+        request.setQueryString("param1=123&param2=" + URLEncoder.encode("äöü߀!:!", CharEncoding.UTF_8)
+                + "&param3=a&param3=b");
+
+        assertNotNull(request.getQueryString());
+        assertEquals(3, request.getParameterMap().size());
+        assertTrue(request.getParameterNames().hasMoreElements());
+        assertEquals("123", request.getParameter("param1"));
+        assertEquals("äöü߀!:!", request.getParameter("param2"));
+        assertArrayEquals(new String[] { "a", "b" }, request.getParameterValues("param3"));
+
+        Map<String, Object> paramMap = new LinkedHashMap<String, Object>();
+        paramMap.put("p1", "a");
+        paramMap.put("p2", new String[] { "b", "c" });
+        paramMap.put("p3", null);
+        paramMap.put("p4", new String[] { null });
+        paramMap.put("p5", 22);
+        request.setParameterMap(paramMap);
+
+        assertEquals("p1=a&p2=b&p2=c&p4=&p5=22", request.getQueryString());
+    }
+
+    @Test
+    public void testSchemeSecure() {
+        assertEquals("http", request.getScheme());
+        assertFalse(request.isSecure());
+
+        request.setScheme("https");
+        assertEquals("https", request.getScheme());
+        assertTrue(request.isSecure());
+    }
+
+    @Test
+    public void testServerNamePort() {
+        assertEquals("localhost", request.getServerName());
+        assertEquals(80, request.getServerPort());
+
+        request.setServerName("myhost");
+        request.setServerPort(12345);
+        assertEquals("myhost", request.getServerName());
+        assertEquals(12345, request.getServerPort());
+    }
+
+    @Test
+    public void testMethod() {
+        assertEquals(HttpConstants.METHOD_GET, request.getMethod());
+
+        request.setMethod(HttpConstants.METHOD_POST);
+        assertEquals(HttpConstants.METHOD_POST, request.getMethod());
+    }
+
+    @Test
+    public void testHeaders() {
+        assertFalse(request.getHeaderNames().hasMoreElements());
+
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.MILLISECOND, 0);
+        long dateValue = calendar.getTimeInMillis();
+
+        request.addHeader("header1", "value1");
+        request.addIntHeader("header2", 5);
+        request.addDateHeader("header3", dateValue);
+
+        assertEquals("value1", request.getHeader("header1"));
+        assertEquals(5, request.getIntHeader("header2"));
+        assertEquals(dateValue, request.getDateHeader("header3"));
+
+        request.setHeader("header1", "value2");
+        request.addIntHeader("header2", 10);
+
+        Enumeration<String> header1Values = request.getHeaders("header1");
+        assertEquals("value2", header1Values.nextElement());
+        assertFalse(header1Values.hasMoreElements());
+
+        Enumeration<String> header2Values = request.getHeaders("header2");
+        assertEquals("5", header2Values.nextElement());
+        assertEquals("10", header2Values.nextElement());
+        assertFalse(header2Values.hasMoreElements());
+    }
+
+    @Test
+    public void testCookies() {
+        assertNull(request.getCookies());
+
+        request.addCookie(new Cookie("cookie1", "value1"));
+        request.addCookie(new Cookie("cookie2", "value2"));
+
+        assertEquals("value1", request.getCookie("cookie1").getValue());
+
+        Cookie[] cookies = request.getCookies();
+        assertEquals(2, cookies.length);
+        assertEquals("value1", cookies[0].getValue());
+        assertEquals("value2", cookies[1].getValue());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponseTest.java b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponseTest.java
new file mode 100644
index 0000000..e794909
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletResponseTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.servlet;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.CharEncoding;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MockSlingHttpServletResponseTest {
+
+    private MockSlingHttpServletResponse response;
+
+    @Before
+    public void setUp() throws Exception {
+        this.response = new MockSlingHttpServletResponse();
+    }
+
+    @Test
+    public void testContentTypeCharset() throws Exception {
+        assertNull(response.getContentType());
+        assertEquals(CharEncoding.ISO_8859_1, response.getCharacterEncoding());
+
+        response.setContentType("text/plain;charset=UTF-8");
+        assertEquals("text/plain;charset=UTF-8", response.getContentType());
+        assertEquals(CharEncoding.UTF_8, response.getCharacterEncoding());
+    }
+
+    @Test
+    public void testContentLength() throws Exception {
+        assertEquals(0, response.getContentLength());
+
+        response.setContentLength(55);
+        assertEquals(55, response.getContentLength());
+    }
+
+    @Test
+    public void testHeaders() throws Exception {
+        assertEquals(0, response.getHeaderNames().size());
+
+        response.addHeader("header1", "value1");
+        response.addIntHeader("header2", 5);
+        response.addDateHeader("header3", System.currentTimeMillis());
+
+        assertEquals(3, response.getHeaderNames().size());
+        assertTrue(response.containsHeader("header1"));
+        assertEquals("value1", response.getHeader("header1"));
+        assertEquals("5", response.getHeader("header2"));
+        assertNotNull(response.getHeader("header3"));
+
+        response.setHeader("header1", "value2");
+        response.addIntHeader("header2", 10);
+
+        assertEquals(3, response.getHeaderNames().size());
+
+        Collection<String> header1Values = response.getHeaders("header1");
+        assertEquals(1, header1Values.size());
+        assertEquals("value2", header1Values.iterator().next());
+
+        Collection<String> header2Values = response.getHeaders("header2");
+        assertEquals(2, header2Values.size());
+        Iterator<String> header2Iterator = header2Values.iterator();
+        assertEquals("5", header2Iterator.next());
+        assertEquals("10", header2Iterator.next());
+
+        response.reset();
+        assertEquals(0, response.getHeaderNames().size());
+    }
+
+    @Test
+    public void testRedirect() throws Exception {
+        response.sendRedirect("/location.html");
+        assertEquals(HttpServletResponse.SC_MOVED_TEMPORARILY, response.getStatus());
+        assertEquals("/location.html", response.getHeader("Location"));
+    }
+
+    @Test
+    public void testSendError() throws Exception {
+        response.sendError(HttpServletResponse.SC_NOT_FOUND);
+        assertEquals(HttpServletResponse.SC_NOT_FOUND, response.getStatus());
+    }
+
+    @Test
+    public void testSetStatus() throws Exception {
+        assertEquals(HttpServletResponse.SC_OK, response.getStatus());
+
+        response.setStatus(HttpServletResponse.SC_BAD_GATEWAY);
+        assertEquals(HttpServletResponse.SC_BAD_GATEWAY, response.getStatus());
+
+        response.reset();
+        assertEquals(HttpServletResponse.SC_OK, response.getStatus());
+    }
+
+    @Test
+    public void testWriteStringContent() throws Exception {
+        final String TEST_CONTENT = "Der Jodelkaiser äöü߀ ᚠᛇᚻ";
+        response.setCharacterEncoding(CharEncoding.UTF_8);
+        response.getWriter().write(TEST_CONTENT);
+        assertEquals(TEST_CONTENT, response.getOutputAsString());
+
+        response.resetBuffer();
+        assertEquals(0, response.getOutputAsString().length());
+    }
+
+    @Test
+    public void testWriteBinaryContent() throws Exception {
+        final byte[] TEST_DATA = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 };
+        response.getOutputStream().write(TEST_DATA);
+        assertArrayEquals(TEST_DATA, response.getOutput());
+
+        response.resetBuffer();
+        assertEquals(0, response.getOutput().length);
+    }
+
+    @Test
+    public void testIsCommitted() throws Exception {
+        assertFalse(response.isCommitted());
+        response.flushBuffer();
+        assertTrue(response.isCommitted());
+    }
+
+    @Test
+    public void testCookies() {
+        assertNull(response.getCookies());
+
+        response.addCookie(new Cookie("cookie1", "value1"));
+        response.addCookie(new Cookie("cookie2", "value2"));
+
+        assertEquals("value1", response.getCookie("cookie1").getValue());
+
+        Cookie[] cookies = response.getCookies();
+        assertEquals(2, cookies.length);
+        assertEquals("value1", cookies[0].getValue());
+        assertEquals("value2", cookies[1].getValue());
+
+        response.reset();
+        assertNull(response.getCookies());
+    }
+
+}
diff --git a/src/test/resources/json-import-samples/content.json b/src/test/resources/json-import-samples/content.json
new file mode 100644
index 0000000..b11dbf9
--- /dev/null
+++ b/src/test/resources/json-import-samples/content.json
@@ -0,0 +1,257 @@
+{
+  "jcr:primaryType": "app:Page",
+  "jcr:createdBy": "admin",
+  "jcr:created": "Thu Aug 07 2014 16:32:59 GMT+0200",
+  "jcr:content": {
+    "jcr:primaryType": "app:PageContent",
+    "jcr:createdBy": "admin",
+    "jcr:title": "English",
+    "app:template": "/apps/sample/templates/homepage",
+    "jcr:created": "Thu Aug 07 2014 16:32:59 GMT+0200",
+    "app:lastModified": "Tue Apr 22 2014 15:11:24 GMT+0200",
+    "dateISO8601String": "2014-04-22T15:11:24.000+02:00",
+    "pageTitle": "Sample Homepage",
+    "sling:resourceType": "sample/components/homepage",
+    "app:designPath": "/etc/designs/sample",
+    "app:lastModifiedBy": "admin",
+    "par": {
+      "jcr:primaryType": "nt:unstructured",
+      "sling:resourceType": "foundation/components/parsys",
+      "colctrl": {
+        "jcr:primaryType": "nt:unstructured",
+        "jcr:createdBy": "admin",
+        "jcr:lastModifiedBy": "admin",
+        "layout": "2;colctrl-lt0",
+        "jcr:created": "Mon Aug 23 2010 22:02:24 GMT+0200",
+        "jcr:lastModified": "Mon Aug 23 2010 22:02:35 GMT+0200",
+        "sling:resourceType": "foundation/components/parsys/colctrl"
+      },
+      "image": {
+        "jcr:primaryType": "nt:unstructured",
+        "jcr:createdBy": "admin",
+        "fileReference": "/content/dam/sample/portraits/jane_doe.jpg",
+        "jcr:lastModifiedBy": "admin",
+        "jcr:created": "Mon Aug 23 2010 22:03:39 GMT+0200",
+        "width": "340",
+        "jcr:lastModified": "Sun Oct 31 2010 21:39:50 GMT+0100",
+        "sling:resourceType": "foundation/components/image",
+        "file": {
+          "jcr:primaryType": "nt:file",
+          "jcr:createdBy": "admin",
+          "jcr:created": "Thu Aug 07 2014 16:32:59 GMT+0200",
+          "jcr:content": {
+            "jcr:primaryType": "nt:resource",
+            "jcr:lastModifiedBy": "anonymous",
+            "jcr:mimeType": "image/jpeg",
+            "jcr:lastModified": "Thu Aug 07 2014 16:32:59 GMT+0200",
+            ":jcr:data": 24377,
+            "jcr:uuid": "eda76d00-b2cd-4b59-878f-c33f71ceaddc"
+          }
+        }
+      },
+      "title_1": {
+        "jcr:primaryType": "nt:unstructured",
+        "jcr:createdBy": "admin",
+        "jcr:title": "Strategic Consulting",
+        "jcr:lastModifiedBy": "admin",
+        "jcr:created": "Mon Aug 23 2010 22:12:08 GMT+0200",
+        "jcr:lastModified": "Wed Oct 27 2010 21:33:24 GMT+0200",
+        "sling:resourceType": "sample/components/title"
+      },
+      "text_1": {
+        "jcr:primaryType": "nt:unstructured",
+        "jcr:createdBy": "admin",
+        "jcr:lastModifiedBy": "admin",
+        "jcr:created": "Sun Oct 31 2010 21:48:04 GMT+0100",
+        "text": "<p><span class=\"Apple-style-span\" style=\"font-size: 12px;\">In&nbsp;today's competitive market, organizations can face several key geometric challenges:<\/span><\/p>\n<ul>\n<li><span class=\"Apple-style-span\" style=\"font-size: 12px;\">Polyhedral Sectioning<\/span><\/li>\n<li><span class=\"Apple-style-span\" style=\"font-size: 12px;\">Triangulation&nbsp;<\/span><\/li>\n<li><span class=\"Apple-style-span\" style=\"font-size: 12px;\">Trigonometric Calculation<\/span><\ [...]
+        "jcr:lastModified": "Sun Oct 31 2010 21:49:06 GMT+0100",
+        "sling:resourceType": "foundation/components/text",
+        "textIsRich": "true"
+      },
+      "col_break12825937554040": {
+        "jcr:primaryType": "nt:unstructured",
+        "controlType": "break",
+        "sling:resourceType": "foundation/components/parsys/colctrl"
+      },
+      "image_0": {
+        "jcr:primaryType": "nt:unstructured",
+        "jcr:createdBy": "admin",
+        "fileReference": "/content/dam/sample/offices/clean_room.jpg",
+        "height": "226",
+        "jcr:lastModifiedBy": "admin",
+        "jcr:created": "Mon Aug 23 2010 22:04:46 GMT+0200",
+        "jcr:lastModified": "Fri Nov 05 2010 10:38:15 GMT+0100",
+        "sling:resourceType": "foundation/components/image",
+        "imageRotate": "0",
+        "file": {
+          "jcr:primaryType": "nt:file",
+          "jcr:createdBy": "admin",
+          "jcr:created": "Thu Aug 07 2014 16:32:59 GMT+0200",
+          "jcr:content": {
+            "jcr:primaryType": "nt:resource",
+            "jcr:lastModifiedBy": "anonymous",
+            "jcr:mimeType": "image/jpeg",
+            "jcr:lastModified": "Thu Aug 07 2014 16:32:59 GMT+0200",
+            ":jcr:data": 21142,
+            "jcr:uuid": "6139077f-191f-4337-aaef-55456ebe6784"
+          }
+        }
+      },
+      "title_2": {
+        "jcr:primaryType": "nt:unstructured",
+        "jcr:createdBy": "admin",
+        "jcr:title": "Shape Technology",
+        "jcr:lastModifiedBy": "admin",
+        "jcr:created": "Mon Aug 23 2010 22:12:13 GMT+0200",
+        "jcr:lastModified": "Tue Oct 26 2010 21:16:29 GMT+0200",
+        "sling:resourceType": "sample/components/title"
+      },
+      "text_0": {
+        "jcr:primaryType": "nt:unstructured",
+        "jcr:createdBy": "admin",
+        "jcr:lastModifiedBy": "admin",
+        "jcr:created": "Mon Aug 23 2010 22:16:30 GMT+0200",
+        "text": "<p>The Sample investment in R&amp;D has done more than solidify our industry leadership role, we have now outpaced our competitors to such an extent that we are in an altogether new space.<\/p>\n<p>This is why our high quality polygons and polyhedra provide the only turnkey solutions across the whole range of euclidean geometry. And our mathematicians are working on the next generation of fractal curves to bring you shapes that are unthinkable today.<\/p>\n<p><\/p>\n<p>< [...]
+        "jcr:lastModified": "Mon Nov 08 2010 20:39:00 GMT+0100",
+        "sling:resourceType": "foundation/components/text",
+        "textIsRich": "true"
+      },
+      "col_end12825937444810": {
+        "jcr:primaryType": "nt:unstructured",
+        "controlType": "end",
+        "sling:resourceType": "foundation/components/parsys/colctrl"
+      }
+    },
+    "header": {
+      "jcr:primaryType": "nt:unstructured",
+      "jcr:title": "trust our experience\r\nto manage your business",
+      "imageReference": "/content/dam/sample/header.png",
+      "text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc eget neque. Nunc condimentum ipsum et orci. Aenean est. Cras eget diam. read more",
+      "sling:resourceType": "sample/components/header"
+    },
+    "newslist": {
+      "jcr:primaryType": "nt:unstructured",
+      "headline": "trust our experience\nto manage your business",
+      "text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc eget neque. Nunc condimentum ipsum et orci. Aenean est. Cras eget diam. read more",
+      "sling:resourceType": "sample/components/listchildren",
+      "listroot": "/content/sample/en/about/news"
+    },
+    "lead": {
+      "jcr:primaryType": "nt:unstructured",
+      "jcr:title": "World Leader in Applied Geometry ",
+      "jcr:lastModifiedBy": "admin",
+      "text": "Lead Text",
+      "title": "Lead Title",
+      "jcr:description": "Sample has been selling and servicing shapes for over 2000 years. From our beginnings as a small vendor of squares and rectangles we have grown our business into a leading global provider of platonic solids and fractals. Join us as we lead geometry into the future.",
+      "jcr:lastModified": "Wed Jan 19 2011 14:35:29 GMT+0100",
+      "sling:resourceType": "sample/components/lead",
+      "app:annotations": {"jcr:primaryType": "nt:unstructured"}
+    },
+    "image": {
+      "jcr:primaryType": "nt:unstructured",
+      "jcr:lastModifiedBy": "admin",
+      "jcr:lastModified": "Wed Oct 27 2010 21:30:59 GMT+0200",
+      "imageRotate": "0"
+    },
+    "carousel": {
+      "jcr:primaryType": "nt:unstructured",
+      "playSpeed": "6000",
+      "jcr:lastModifiedBy": "admin",
+      "pages": [
+        "/content/sample/en/events/techsummit",
+        "/content/sample/en/events/userconf",
+        "/content/sample/en/events/shapecon",
+        "/content/sample/en/events/dsc"
+      ],
+      "jcr:lastModified": "Tue Oct 05 2010 14:14:27 GMT+0200",
+      "transTime": "1000",
+      "sling:resourceType": "foundation/components/carousel",
+      "listFrom": "static"
+    },
+    "rightpar": {
+      "jcr:primaryType": "nt:unstructured",
+      "sling:resourceType": "foundation/components/parsys",
+      "teaser": {
+        "jcr:primaryType": "nt:unstructured",
+        "jcr:createdBy": "admin",
+        "jcr:lastModifiedBy": "admin",
+        "jcr:created": "Tue Jan 25 2011 11:30:09 GMT+0100",
+        "campaignpath": "/content/campaigns/sample",
+        "jcr:lastModified": "Wed Feb 02 2011 08:40:30 GMT+0100",
+        "sling:resourceType": "personalization/components/teaser"
+      }
+    }
+  },
+  "toolbar": {
+    "jcr:primaryType": "app:Page",
+    "jcr:createdBy": "admin",
+    "jcr:created": "Thu Aug 07 2014 16:33:00 GMT+0200",
+    "jcr:content": {
+      "jcr:primaryType": "app:PageContent",
+      "subtitle": "Contains the toolbar",
+      "jcr:createdBy": "admin",
+      "jcr:title": "Toolbar",
+      "app:template": "/apps/sample/templates/contentpage",
+      "jcr:created": "Thu Aug 07 2014 16:33:00 GMT+0200",
+      "app:lastModified": "Wed Aug 25 2010 22:51:02 GMT+0200",
+      "hideInNav": "true",
+      "sling:resourceType": "sample/components/contentpage",
+      "app:lastModifiedBy": "admin",
+      "par": {
+        "jcr:primaryType": "nt:unstructured",
+        "sling:resourceType": "foundation/components/parsys"
+      },
+      "rightpar": {
+        "jcr:primaryType": "nt:unstructured",
+        "sling:resourceType": "foundation/components/iparsys",
+        "iparsys_fake_par": {
+          "jcr:primaryType": "nt:unstructured",
+          "sling:resourceType": "foundation/components/iparsys/par"
+        }
+      }
+    },
+    "profiles": {
+      "jcr:primaryType": "app:Page",
+      "jcr:createdBy": "admin",
+      "jcr:created": "Thu Aug 07 2014 16:33:00 GMT+0200",
+      "jcr:content": {
+        "jcr:primaryType": "app:PageContent",
+        "jcr:createdBy": "admin",
+        "jcr:title": "Profiles",
+        "app:template": "/apps/sample/templates/contentpage",
+        "jcr:created": "Thu Aug 07 2014 16:33:00 GMT+0200",
+        "app:lastModified": "Thu Nov 05 2009 20:27:13 GMT+0100",
+        "hideInNav": true,
+        "sling:resourceType": "sample/components/contentpage",
+        "app:lastModifiedBy": "admin",
+        "longProp": 1234567890123,
+        "decimalProp": 1.2345,
+        "booleanProp": true,
+        "longPropMulti": [1234567890123,55],
+        "decimalPropMulti": [1.2345,1.1],
+        "booleanPropMulti": [true,false],
+        "par": {
+          "jcr:primaryType": "nt:unstructured",
+          "sling:resourceType": "foundation/components/parsys",
+          "textimage": {
+            "jcr:primaryType": "nt:unstructured",
+            "sling:resourceType": "foundation/components/textimage"
+          },
+          "mygadgets": {
+            "jcr:primaryType": "nt:unstructured",
+            "gadgets": "http://customer.meteogroup.de/meteogroup/gadgets/wetter24.xml\nhttp://germanweatherradar.googlecode.com/svn/trunk/german-weather-radar.xml\nhttp://www.digitalpowered.info/gadget/ski.pictures.xml\nhttp://www.canbuffi.de/gadgets/clock/clock.xml",
+            "sling:resourceType": "personalization/components/mygadgets"
+          }
+        },
+        "rightpar": {
+          "jcr:primaryType": "nt:unstructured",
+          "sling:resourceType": "foundation/components/iparsys",
+          "iparsys_fake_par": {
+            "jcr:primaryType": "nt:unstructured",
+            "sling:resourceType": "foundation/components/iparsys/par"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/src/test/resources/json-import-samples/dam.json b/src/test/resources/json-import-samples/dam.json
new file mode 100644
index 0000000..04f1089
--- /dev/null
+++ b/src/test/resources/json-import-samples/dam.json
@@ -0,0 +1,156 @@
+{
+  "jcr:primaryType": "sling:OrderedFolder",
+  "jcr:createdBy": "admin",
+  "jcr:title": "Sample",
+  "jcr:created": "Thu Aug 07 2014 16:32:56 GMT+0200",
+  "portraits": {
+    "jcr:primaryType": "sling:OrderedFolder",
+    "jcr:createdBy": "admin",
+    "jcr:title": "Portraits",
+    "jcr:created": "Thu Aug 07 2014 16:32:57 GMT+0200",
+    "scott_reynolds.jpg": {
+      "jcr:primaryType": "dam:Asset",
+      "jcr:mixinTypes": ["mix:versionable"],
+      "jcr:createdBy": "admin",
+      "jcr:versionHistory": "d56a56fa-2a34-487d-b349-53b51033ffc4",
+      "jcr:predecessors": ["f08611ae-e7ed-4b85-99fa-2c4a623e49c2"],
+      "jcr:created": "Thu Aug 07 2014 16:32:58 GMT+0200",
+      "jcr:baseVersion": "f08611ae-e7ed-4b85-99fa-2c4a623e49c2",
+      "jcr:isCheckedOut": true,
+      "jcr:uuid": "442d55b6-d534-4faf-9394-c9c20d095985",
+      "jcr:content": {
+        "jcr:primaryType": "dam:AssetContent",
+        "jcr:lastModifiedBy": "admin",
+        "app:name": "scott_reynolds.jpg",
+        "jcr:lastModified": "Wed May 08 2013 10:21:57 GMT+0200",
+        "app:parentPath": "/content/dam/sample/portraits",
+        "renditions": {
+          "jcr:primaryType": "nt:folder",
+          "jcr:createdBy": "admin",
+          "jcr:created": "Thu Aug 07 2014 16:32:58 GMT+0200",
+          "dam.thumbnail.48.48.png": {
+            "jcr:primaryType": "nt:file",
+            "jcr:createdBy": "admin",
+            "jcr:created": "Thu Aug 07 2014 16:32:58 GMT+0200",
+            "jcr:content": {
+              "jcr:primaryType": "nt:resource",
+              "jcr:lastModifiedBy": "admin",
+              "jcr:mimeType": "image/png",
+              "jcr:lastModified": "Thu Aug 07 2014 16:32:58 GMT+0200",
+              ":jcr:data": 5071,
+              "jcr:uuid": "1a8cda3f-ac06-4779-89e2-55e3929cfc3e"
+            }
+          },
+          "dam.thumbnail.140.100.png": {
+            "jcr:primaryType": "nt:file",
+            "jcr:createdBy": "admin",
+            "jcr:created": "Thu Aug 07 2014 16:32:58 GMT+0200",
+            "jcr:content": {
+              "jcr:primaryType": "nt:resource",
+              "jcr:lastModifiedBy": "admin",
+              "jcr:mimeType": "image/png",
+              "jcr:lastModified": "Thu Aug 07 2014 16:32:58 GMT+0200",
+              ":jcr:data": 34023,
+              "jcr:uuid": "5cbcbf47-a33e-4f33-b9d9-55c9d5f7dd85"
+            }
+          },
+          "original": {
+            "jcr:primaryType": "nt:file",
+            "jcr:createdBy": "admin",
+            "jcr:created": "Thu Aug 07 2014 16:32:58 GMT+0200",
+            "jcr:content": {
+              "jcr:primaryType": "nt:resource",
+              "jcr:lastModifiedBy": "admin",
+              "jcr:mimeType": "image/jpeg",
+              "jcr:lastModified": "Thu Aug 07 2014 16:32:58 GMT+0200",
+              ":jcr:data": 46825,
+              "jcr:uuid": "5673bb2d-0fc3-485d-9767-57241c1b4a30"
+            }
+          },
+          "dam.thumbnail.319.319.png": {
+            "jcr:primaryType": "nt:file",
+            "jcr:createdBy": "admin",
+            "jcr:created": "Thu Aug 07 2014 16:32:58 GMT+0200",
+            "jcr:content": {
+              "jcr:primaryType": "nt:resource",
+              "jcr:lastModifiedBy": "admin",
+              "jcr:mimeType": "image/png",
+              "jcr:lastModified": "Thu Aug 07 2014 16:32:58 GMT+0200",
+              ":jcr:data": 162594,
+              "jcr:uuid": "176a4ba8-c03b-4f90-815e-d84070d15dc2"
+            }
+          }
+        },
+        "metadata": {
+          "jcr:primaryType": "nt:unstructured",
+          "jcr:mixinTypes": ["app:Taggable"],
+          "dam:UserComment": "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000 [...]
+          "dam:ExposureCompensation": 2,
+          "tiff:Compression": 6,
+          "tiff:Make": "Canon\u0000",
+          "dam:Physicalwidthininches": 4.483333110809326,
+          "exif:CustomRendered": 0,
+          "dam:JpgFromRawStart": 1054,
+          "dam:Fileformat": "JPEG",
+          "exif:MaxApertureValue": 4.64385986328125,
+          "dam:Progressive": "no",
+          "exif:FNumber": 5,
+          "tiff:ImageLength": 595,
+          "exif:FlashpixVersion": "0100",
+          "tiff:YResolution": 180,
+          "dam:OtherImageStart": 1054,
+          "exif:FocalLength": 39,
+          "exif:ColorSpace": 65535,
+          "jcr:lastModifiedBy": "admin",
+          "xmp:CreatorTool": "Adobe Photoshop 7.0",
+          "dam:SensingMethod": 2,
+          "dam:extracted": "Wed Oct 06 2010 15:53:22 GMT+0200",
+          "dam:ApertureValue": 4.64385986328125,
+          "dc:format": "image/jpeg",
+          "dam:Bitsperpixel": 24,
+          "exif:FileSource": 3,
+          "dam:OtherImageLength": 2788,
+          "exif:ExifVersion": "0221",
+          "tiff:YCbCrPositioning": 1,
+          "dam:MIMEtype": "image/jpeg",
+          "tiff:Orientation": 1,
+          "dam:FocalPlaneXResolution": 3443.946188340807,
+          "dam:JpgFromRawLength": 2788,
+          "dam:Physicalwidthindpi": 180,
+          "dam:Physicalheightindpi": 180,
+          "exif:Flash": 0,
+          "exif:CompressedBitsPerPixel": 3,
+          "tiff:ResolutionUnit": 2,
+          "dam:ShutterSpeedValue": 5.906890869140625,
+          "exif:ComponentsConfiguration": ["[B@d19c55"],
+          "dam:FocalPlaneResolutionUnit": 2,
+          "dc:modified": "Wed Oct 06 2010 15:53:23 GMT+0200",
+          "dam:Numberofimages": 1,
+          "exif:ExposureMode": 0,
+          "exif:ExposureTime": 0.016666666666666666,
+          "tiff:XResolution": 180,
+          "dam:ExifOffset": 220,
+          "dam:PreviewImageStart": 1054,
+          "exif:WhiteBalance": 0,
+          "app:tags": [
+            "stockphotography:business/business_people",
+            "properties:style/color",
+            "properties:orientation/landscape"
+          ],
+          "jcr:lastModified": "Wed May 08 2013 10:21:57 GMT+0200",
+          "dam:Numberoftextualcomments": 0,
+          "xmp:ModifyDate": "Sat Oct 01 2005 15:16:30 GMT+0200",
+          "tiff:ImageWidth": 807,
+          "exif:DateTimeOriginal": "Sat Oct 01 2005 15:16:30 GMT+0200",
+          "dam:ModifyDate": "Thu Oct 20 2005 12:56:51 GMT+0200",
+          "tiff:Model": "Canon EOS 300D DIGITAL\u0000",
+          "exif:MeteringMode": 5,
+          "exif:SceneCaptureType": 0,
+          "dc:title": "Scott Reynolds",
+          "dam:PreviewImageLength": 2788,
+          "dam:FocalPlaneYResolution": 3442.016806722689
+        }
+      }
+    }
+  }
+}
diff --git a/src/test/resources/sample-image.gif b/src/test/resources/sample-image.gif
new file mode 100644
index 0000000..8b310f6
Binary files /dev/null and b/src/test/resources/sample-image.gif differ

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 21/26: SLING-4229 add test cases for deep path access support in sling-mock as well

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit e72ad4b2b0cc40e8921070ea481417b84374dff4
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Dec 9 13:09:54 2014 +0000

    SLING-4229 add test cases for deep path access support in sling-mock as well
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1644042 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                              |  2 +-
 .../AbstractSlingCrudResourceResolverTest.java       | 20 +++++++++++++++++++-
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index c3621a9..5e74b32 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,7 +61,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.resourceresolver-mock</artifactId>
-            <version>1.0.0</version>
+            <version>1.0.1-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
 
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractSlingCrudResourceResolverTest.java b/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractSlingCrudResourceResolverTest.java
index 20ed560..cf44b9e 100644
--- a/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractSlingCrudResourceResolverTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractSlingCrudResourceResolverTest.java
@@ -45,6 +45,7 @@ import org.junit.Before;
 import org.junit.Test;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 
 /**
  * Implements simple write and read resource and values test. Sling CRUD API is
@@ -90,7 +91,9 @@ public abstract class AbstractSlingCrudResourceResolverTest {
         props.put("binaryProp", new ByteArrayInputStream(BINARY_VALUE));
         Resource node1 = this.resourceResolver.create(rootNode, "node1", props);
 
-        this.resourceResolver.create(node1, "node11", ValueMap.EMPTY);
+        resourceResolver.create(node1, "node11", ImmutableMap.<String, Object>builder()
+                .put("stringProp11", STRING_VALUE)
+                .build());
         this.resourceResolver.create(node1, "node12", ValueMap.EMPTY);
 
         this.resourceResolver.commit();
@@ -136,6 +139,21 @@ public abstract class AbstractSlingCrudResourceResolverTest {
     }
 
     @Test
+    public void testSimpleProperties_DeepPathAccess() throws IOException {
+        Resource resource1 = resourceResolver.getResource(testRoot.getPath());
+        assertNotNull(resource1);
+        assertEquals(testRoot.getName(), resource1.getName());
+
+        ValueMap props = ResourceUtil.getValueMap(resource1);
+        assertEquals(STRING_VALUE, props.get("node1/stringProp", String.class));
+        assertArrayEquals(STRING_ARRAY_VALUE, props.get("node1/stringArrayProp", String[].class));
+        assertEquals((Integer) INTEGER_VALUE, props.get("node1/integerProp", Integer.class));
+        assertEquals(DOUBLE_VALUE, props.get("node1/doubleProp", Double.class), 0.0001);
+        assertEquals(BOOLEAN_VALUE, props.get("node1/booleanProp", Boolean.class));
+        assertEquals(STRING_VALUE, props.get("node1/node11/stringProp11", String.class));
+    }
+    
+    @Test
     public void testDateProperty() throws IOException {
         Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1");
         ValueMap props = ResourceUtil.getValueMap(resource1);

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 16/26: set to released version now available on maven central

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 2f5faf498a5fdf1f4feb8a5e8b37889ab99b266d
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Oct 22 19:33:51 2014 +0000

    set to released version now available on maven central
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1633690 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pom.xml b/pom.xml
index faea81d..66a28ce 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,19 +49,19 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
-            <version>1.0.1-SNAPSHOT</version>
+            <version>1.0.0</version>
             <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.jcr-mock</artifactId>
-            <version>1.0.1-SNAPSHOT</version>
+            <version>1.0.0</version>
             <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.resourceresolver-mock</artifactId>
-            <version>1.0.1-SNAPSHOT</version>
+            <version>1.0.0</version>
             <scope>compile</scope>
         </dependency>
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 08/26: SLING-4042 add README files

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 4fc4bafec3e0f3c437d090e67de53b2dea7abe20
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Thu Oct 16 19:09:39 2014 +0000

    SLING-4042 add README files
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1632415 13f79535-47bb-0310-9956-ffa450edef68
---
 README.txt | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..0de2b92
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,6 @@
+Apache Sling Testing Sling Mock
+
+Mock implementation of selected Sling APIs.
+
+Documentation:
+http://sling.apache.org/documentation/development/sling-mock.html

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 24/26: update to released versions

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 47cc45e04986a11341e45eb8fb43ebc4183f841e
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Dec 9 23:05:49 2014 +0000

    update to released versions
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1644228 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pom.xml b/pom.xml
index 5e74b32..84bc81a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,19 +49,19 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
-            <version>1.0.1-SNAPSHOT</version>
+            <version>1.1.0</version>
             <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.jcr-mock</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.resourceresolver-mock</artifactId>
-            <version>1.0.1-SNAPSHOT</version>
+            <version>1.1.0</version>
             <scope>compile</scope>
         </dependency>
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 13/26: update dependencies in release process to next snapshot version

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 5b0b3fe1782d360e081d1a37ba2078db104693cf
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Fri Oct 17 08:22:31 2014 +0000

    update dependencies in release process to next snapshot version
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1632505 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pom.xml b/pom.xml
index f9f16a1..e50cd17 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,19 +49,19 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
-            <version>1.0.0</version>
+            <version>1.0.1-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.jcr-mock</artifactId>
-            <version>1.0.0</version>
+            <version>1.0.1-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.resourceresolver-mock</artifactId>
-            <version>1.0.0</version>
+            <version>1.0.1-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 07/26: SLING-4042 make sure JCR mock supports accessing data using multiple sessions

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 3d36daf5afdd7b7a1a687ce4a8efec1617888bcf
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Thu Oct 16 17:53:47 2014 +0000

    SLING-4042 make sure JCR mock supports accessing data using multiple sessions
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1632397 13f79535-47bb-0310-9956-ffa450edef68
---
 .../resource/MultipleResourceResolverTest.java}    | 15 ++---
 .../AbstractMultipleResourceResolverTest.java      | 66 ++++++++++++++++++++++
 ...Test.java => MultipleResourceResolverTest.java} | 11 +---
 .../resource/SlingCrudResourceResolverTest.java    |  7 ---
 4 files changed, 72 insertions(+), 27 deletions(-)

diff --git a/src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/SlingCrudResourceResolverTest.java b/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/resource/MultipleResourceResolverTest.java
similarity index 63%
copy from src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/SlingCrudResourceResolverTest.java
copy to src/test/java/org/apache/sling/testing/mock/sling/jcrmock/resource/MultipleResourceResolverTest.java
index 5bca11e..cc02db4 100644
--- a/src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/SlingCrudResourceResolverTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/sling/jcrmock/resource/MultipleResourceResolverTest.java
@@ -16,23 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.testing.mock.sling.rrmock.resource;
+package org.apache.sling.testing.mock.sling.jcrmock.resource;
 
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.testing.mock.sling.MockSling;
 import org.apache.sling.testing.mock.sling.ResourceResolverType;
-import org.apache.sling.testing.mock.sling.resource.AbstractSlingCrudResourceResolverTest;
+import org.apache.sling.testing.mock.sling.resource.AbstractMultipleResourceResolverTest;
 
-public class SlingCrudResourceResolverTest extends AbstractSlingCrudResourceResolverTest {
+public class MultipleResourceResolverTest extends AbstractMultipleResourceResolverTest {
 
     @Override
     protected ResourceResolverType getResourceResolverType() {
-        return ResourceResolverType.RESOURCERESOLVER_MOCK;
-    }
-
-    @Override
-    protected ResourceResolver newResourceResolver() {
-        return MockSling.newResourceResolver(getResourceResolverType());
+        return ResourceResolverType.JCR_MOCK;
     }
 
 }
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractMultipleResourceResolverTest.java b/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractMultipleResourceResolverTest.java
new file mode 100644
index 0000000..1ce615e
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/resource/AbstractMultipleResourceResolverTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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 org.apache.sling.testing.mock.sling.resource;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Tests content access accross multiple resource resolvers.
+ */
+public abstract class AbstractMultipleResourceResolverTest {
+
+    protected abstract ResourceResolverType getResourceResolverType();
+
+    protected ResourceResolverFactory newResourceResolerFactory() {
+        return MockSling.newResourceResolverFactory(getResourceResolverType());
+    }
+    
+    @Test
+    public void testMultipleResourceResolver() throws Exception {
+        ResourceResolverFactory factory = newResourceResolerFactory();
+        ResourceResolver resolver1 = factory.getResourceResolver(null);
+        ResourceResolver resolver2 = factory.getResourceResolver(null);
+        
+        // add a resource in resolver 1
+        Resource root = resolver1.getResource("/");
+        resolver1.create(root, "test", ImmutableMap.<String, Object>of());
+        resolver1.commit();
+        
+        // try to get resource in resolver 2
+        Resource testResource2 = resolver2.getResource("/test");
+        assertNotNull(testResource2);
+        
+        // delete resource and make sure it is removed in resolver 1 as well
+        resolver2.delete(testResource2);
+        resolver2.commit();
+        
+        assertNull(resolver1.getResource("/test"));
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/SlingCrudResourceResolverTest.java b/src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/MultipleResourceResolverTest.java
similarity index 71%
copy from src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/SlingCrudResourceResolverTest.java
copy to src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/MultipleResourceResolverTest.java
index 5bca11e..64aab30 100644
--- a/src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/SlingCrudResourceResolverTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/MultipleResourceResolverTest.java
@@ -18,21 +18,14 @@
  */
 package org.apache.sling.testing.mock.sling.rrmock.resource;
 
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.testing.mock.sling.MockSling;
 import org.apache.sling.testing.mock.sling.ResourceResolverType;
-import org.apache.sling.testing.mock.sling.resource.AbstractSlingCrudResourceResolverTest;
+import org.apache.sling.testing.mock.sling.resource.AbstractMultipleResourceResolverTest;
 
-public class SlingCrudResourceResolverTest extends AbstractSlingCrudResourceResolverTest {
+public class MultipleResourceResolverTest extends AbstractMultipleResourceResolverTest {
 
     @Override
     protected ResourceResolverType getResourceResolverType() {
         return ResourceResolverType.RESOURCERESOLVER_MOCK;
     }
 
-    @Override
-    protected ResourceResolver newResourceResolver() {
-        return MockSling.newResourceResolver(getResourceResolverType());
-    }
-
 }
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/SlingCrudResourceResolverTest.java b/src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/SlingCrudResourceResolverTest.java
index 5bca11e..20ab589 100644
--- a/src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/SlingCrudResourceResolverTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/sling/rrmock/resource/SlingCrudResourceResolverTest.java
@@ -18,8 +18,6 @@
  */
 package org.apache.sling.testing.mock.sling.rrmock.resource;
 
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.testing.mock.sling.MockSling;
 import org.apache.sling.testing.mock.sling.ResourceResolverType;
 import org.apache.sling.testing.mock.sling.resource.AbstractSlingCrudResourceResolverTest;
 
@@ -30,9 +28,4 @@ public class SlingCrudResourceResolverTest extends AbstractSlingCrudResourceReso
         return ResourceResolverType.RESOURCERESOLVER_MOCK;
     }
 
-    @Override
-    protected ResourceResolver newResourceResolver() {
-        return MockSling.newResourceResolver(getResourceResolverType());
-    }
-
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 25/26: [maven-release-plugin] prepare release org.apache.sling.testing.sling-mock-1.1.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit fccd947c71e01847ad00877ab9480d2b3ba6139f
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Dec 9 23:06:34 2014 +0000

    [maven-release-plugin] prepare release org.apache.sling.testing.sling-mock-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1644229 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 84bc81a..30b7367 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
     </parent>
 
     <artifactId>org.apache.sling.testing.sling-mock</artifactId>
-    <version>1.0.1-SNAPSHOT</version>
+    <version>1.1.0</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling Testing Sling Mock</name>
@@ -39,9 +39,9 @@
     </properties>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/trunk/testing/mocks/sling-mock</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.sling-mock-1.1.0</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.sling-mock-1.1.0</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.testing.sling-mock-1.1.0</url>
     </scm>
 
     <dependencies>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-sling-mock] 15/26: SLING-4086 SlingHttpServlerRequest should support getResourceBundle() methods

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 9442dd81f20d5585f49408f0786c1a8aabfdb737
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Oct 21 20:09:55 2014 +0000

    SLING-4086 SlingHttpServlerRequest should support getResourceBundle() methods
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/sling-mock@1633444 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            |  8 +++-
 .../mock/sling/context/SlingContextImpl.java       |  2 +-
 .../sling/servlet/MockSlingHttpServletRequest.java | 56 +++++++++++++++++-----
 .../servlet/MockSlingHttpServletRequestTest.java   | 39 ++++++++++++++-
 4 files changed, 90 insertions(+), 15 deletions(-)

diff --git a/pom.xml b/pom.xml
index e50cd17..faea81d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -132,7 +132,13 @@
             <version>1.2.2</version>
             <scope>compile</scope>
         </dependency>
-    
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.i18n</artifactId>
+            <version>2.2.4</version>
+            <scope>compile</scope>
+        </dependency>
+
         <dependency>
             <groupId>commons-collections</groupId>
             <artifactId>commons-collections</artifactId>
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java b/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
index 907f804..65076aa 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
@@ -215,7 +215,7 @@ public class SlingContextImpl {
      */
     public final MockSlingHttpServletRequest request() {
         if (this.request == null) {
-            this.request = new MockSlingHttpServletRequest(this.resourceResolver());
+            this.request = new MockSlingHttpServletRequest(this.resourceResolver(), this.bundleContext());
 
             // initialize sling bindings
             SlingBindings bindings = new SlingBindings();
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequest.java b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequest.java
index 4444945..eaad0bf 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequest.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequest.java
@@ -29,6 +29,7 @@ import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.ListResourceBundle;
 import java.util.Locale;
 import java.util.Map;
 import java.util.ResourceBundle;
@@ -59,14 +60,19 @@ import org.apache.sling.api.request.RequestProgressTracker;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.servlets.HttpConstants;
+import org.apache.sling.i18n.ResourceBundleProvider;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
 import org.apache.sling.testing.mock.sling.MockSling;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
 
 /**
  * Mock {@link SlingHttpServletRequest} implementation.
  */
 public class MockSlingHttpServletRequest extends SlingAdaptable implements SlingHttpServletRequest {
 
-    private ResourceResolver resourceResolver;
+    private final ResourceResolver resourceResolver;
+    private final BundleContext bundleContext;
     private RequestPathInfo requestPathInfo = new MockRequestPathInfo();
     private Map<String, Object> attributeMap = new HashMap<String, Object>();
     private Map<String, String[]> parameterMap = new LinkedHashMap<String, String[]>();
@@ -80,19 +86,34 @@ public class MockSlingHttpServletRequest extends SlingAdaptable implements Sling
     private String method = HttpConstants.METHOD_GET;
     private final HeaderSupport headerSupport = new HeaderSupport();
     private final CookieSupport cookieSupport = new CookieSupport();
+    
+    private static final ResourceBundle EMPTY_RESOURCE_BUNDLE = new ListResourceBundle() {
+        @Override
+        protected Object[][] getContents() {
+            return new Object[0][0];
+        }
+    };
 
     /**
      * Instantiate with default resource resolver
      */
     public MockSlingHttpServletRequest() {
-        this.resourceResolver = MockSling.newResourceResolver();
+        this(MockSling.newResourceResolver());
     }
 
     /**
      * @param resourceResolver Resource resolver
      */
     public MockSlingHttpServletRequest(ResourceResolver resourceResolver) {
+        this(resourceResolver, MockOsgi.newBundleContext());
+    }
+
+    /**
+     * @param resourceResolver Resource resolver
+     */
+    public MockSlingHttpServletRequest(ResourceResolver resourceResolver, BundleContext bundleContext) {
         this.resourceResolver = resourceResolver;
+        this.bundleContext = bundleContext;
     }
 
     @Override
@@ -421,6 +442,27 @@ public class MockSlingHttpServletRequest extends SlingAdaptable implements Sling
         cookieSupport.addCookie(cookie);
     }
 
+    @Override
+    public ResourceBundle getResourceBundle(Locale locale) {
+        return getResourceBundle(null, locale);
+    }
+
+    @Override
+    public ResourceBundle getResourceBundle(String baseName, Locale locale) {
+        // check of ResourceBundleProvider is registered in mock OSGI context
+        ResourceBundle resourceBundle = null;
+        ServiceReference serviceReference = bundleContext.getServiceReference(ResourceBundleProvider.class.getName());
+        if (serviceReference != null) {
+            ResourceBundleProvider provider = (ResourceBundleProvider)bundleContext.getService(serviceReference);
+            resourceBundle = provider.getResourceBundle(baseName, locale);
+        }       
+        // if no ResourceBundleProvider exists return empty bundle
+        if (resourceBundle == null) {
+            resourceBundle = EMPTY_RESOURCE_BUNDLE;
+        }
+        return resourceBundle;
+    }
+    
     // --- unsupported operations ---
 
     @Override
@@ -459,16 +501,6 @@ public class MockSlingHttpServletRequest extends SlingAdaptable implements Sling
     }
 
     @Override
-    public ResourceBundle getResourceBundle(Locale pLocale) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public ResourceBundle getResourceBundle(String baseName, Locale locale) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public String getResponseContentType() {
         throw new UnsupportedOperationException();
     }
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequestTest.java b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequestTest.java
index 7539d09..8c868b7 100644
--- a/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequestTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/sling/servlet/MockSlingHttpServletRequestTest.java
@@ -25,14 +25,18 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.util.Calendar;
 import java.util.Enumeration;
 import java.util.LinkedHashMap;
+import java.util.ListResourceBundle;
 import java.util.Locale;
 import java.util.Map;
+import java.util.ResourceBundle;
 
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpSession;
@@ -41,11 +45,14 @@ import org.apache.commons.lang3.CharEncoding;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.servlets.HttpConstants;
+import org.apache.sling.i18n.ResourceBundleProvider;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.BundleContext;
 
 @RunWith(MockitoJUnitRunner.class)
 public class MockSlingHttpServletRequestTest {
@@ -54,12 +61,13 @@ public class MockSlingHttpServletRequestTest {
     private ResourceResolver resourceResolver;
     @Mock
     private Resource resource;
+    private BundleContext bundleContext = MockOsgi.newBundleContext();
 
     private MockSlingHttpServletRequest request;
 
     @Before
     public void setUp() throws Exception {
-        request = new MockSlingHttpServletRequest(resourceResolver);
+        request = new MockSlingHttpServletRequest(resourceResolver, bundleContext);
     }
 
     @Test
@@ -212,5 +220,34 @@ public class MockSlingHttpServletRequestTest {
         assertEquals("value1", cookies[0].getValue());
         assertEquals("value2", cookies[1].getValue());
     }
+    
+    @Test
+    public void testDefaultResourceBundle() {
+        ResourceBundle bundle = request.getResourceBundle(Locale.US);
+        assertNotNull(bundle);
+        assertFalse(bundle.getKeys().hasMoreElements());
+    }
+
+    @Test
+    public void testResourceBundleFromProvider() {
+        ResourceBundleProvider provider = mock(ResourceBundleProvider.class);
+        bundleContext.registerService(ResourceBundleProvider.class.getName(), provider, null);
+        when(provider.getResourceBundle("base1", Locale.US)).thenReturn(new ListResourceBundle() {
+            @Override
+            protected Object[][] getContents() {
+                return new Object[][] {
+                        { "key1", "value1" }
+                };
+            }
+        });        
+        
+        ResourceBundle bundle = request.getResourceBundle("base1", Locale.US);
+        assertNotNull(bundle);
+        assertEquals("value1", bundle.getString("key1"));
+
+        ResourceBundle bundle2 = request.getResourceBundle("base2", Locale.US);
+        assertNotNull(bundle2);
+        assertFalse(bundle2.getKeys().hasMoreElements());
+    }
 
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.