Move Sling to new TLP location

git-svn-id: https://svn.eu.apache.org/repos/asf/sling/tags/org.apache.sling.launchpad.testing-5-incubator@785979 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..861d0ce
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,8 @@
+Apache Sling Launchpad Testing
+Copyright 2008-2009 The Apache Software Foundation
+
+Apache Sling is based on source code originally developed 
+by Day Software (http://www.day.com/).
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..5ed48bf
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,125 @@
+Apache Sling Launchpad Testing module
+
+This module builds a Sling webapp using bundles from the trunk, and
+runs integration tests (that were previously in the launchpad/webapp
+module) on them.  
+
+
+Disclaimer
+==========
+Apache Sling is an effort undergoing incubation at The Apache Software Foundation (ASF),
+sponsored by the Apache Jackrabbit PMC. Incubation is required of all newly accepted
+projects until a further review indicates that the infrastructure, communications,
+and decision making process have stabilized in a manner consistent with other
+successful ASF projects. While incubation status is not necessarily a reflection of
+the completeness or stability of the code, it does indicate that the project has yet
+to be fully endorsed by the ASF.
+
+Getting Started
+===============
+
+This component uses a Maven 2 (http://maven.apache.org/) build
+environment. It requires a Java 5 JDK (or higher) and Maven (http://maven.apache.org/)
+2.0.7 or later. We recommend to use the latest Maven version.
+
+If you have Maven 2 installed, you can compile and
+package the jar using the following command:
+
+    mvn package
+
+See the Maven 2 documentation for other build features.
+
+The latest source code for this component is available in the
+Subversion (http://subversion.tigris.org/) source repository of
+the Apache Software Foundation. If you have Subversion installed,
+you can checkout the latest source using the following command:
+
+    svn checkout http://svn.apache.org/repos/asf/incubator/sling/trunk/launchpad/webapp
+
+See the Subversion documentation for other source control features.
+
+
+How to run this
+---------------
+  NOTE: "mvn clean" does not delete the "sling" work directory - make sure to 
+  delete it manually if you want to start from a clean state.
+
+1) Build all Sling bundles
+
+  cd <top of the Sling source code tree>
+  mvn clean install
+  
+2) Build and run this
+
+  cd launchpad/testing
+  mvn clean package jetty:run
+  
+Once the webapp starts, http://localhost:8888/system/console should display the Felix
+OSGi console.
+
+4) Test node creation and display
+To create a node with curl:
+
+	 curl -D - -Ftitle=something http://admin:admin@localhost:8888/testing/this
+	 
+Then, http://admin:admin@localhost:8888/testing/this should display a default HTML
+representation, including the value of the "title" property.
+
+Add a txt or json extension to see other output formats.
+
+Integration tests
+-----------------
+This module provides a number of integration tests, that run automatically when
+doing a full build, and test Sling via its client HTTP interfaces.
+
+These tests can also be run against another instance of Sling, for example to
+test it in another web container than the embedded Jetty that is used during the
+Maven build.
+
+See pom.xml for the parameters that control these integration tests. Here's an
+example of running them against a Sling instance running on host xyzzy, port 1234,
+with the Sling webapp mounted under /foo:
+
+   mvn -o -s /dev/null test \
+    -Dhttp.port=1234 \
+    -Dtest.host=xyzzy \
+    -Dhttp.base.path=foo \
+    -Dwebdav.workspace.path=foo/dav/default \
+    -Dtest=**/integrationtest/**/*Test.java
+
+The  -s /dev/null parameter disables all your local Maven settings, to make sure
+they don't interfere. Feel free to remove that if you know what you're doing.
+
+To run a single test, other values can be used for the "-Dtest" parameter.
+
+This is very useful during development: you can leave a Sling webapp instance
+running, update bundles in it using the mvn autoInstallBundle profile, and run
+specific integration tests quickly from another terminal.
+
+JCR Install Integration tests
+-----------------------------
+
+This module also contains integration tests for the JCR Install module. These
+tests are disabled by default, since they may not be of general interest. To
+include the JCR Install tests in the integration tests run enable the
+jcrinstall-tests profile such as in
+
+   mvn -P jcrinstall-tests integration-test
+   
+*** WARNING: the jcrinstall-tests do not work in revision 741168, due to changes
+in the start levels. They can be run according to the scenario below, if you 
+change the default bundles start level to 30, after starting the Sling instance
+with mvn jetty:run, from http://localhost:8888/system/console/vmstat. ***     
+
+To run the jcrinstall integration tests quickly, without having to start the
+webapp first:
+
+1. Run mvn clean package jetty:run -P jcrinstall-tests in a first console
+
+(1.5 see WARNING above - adjust the default bundles start level)
+
+2. In another console run
+
+  mvn test -Pjcrinstall-tests  -Dtest=**/integrationtest/jcrinstall/**/*Test.java
+  
+       
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..dc9dd33
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,518 @@
+<?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/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>5-incubator</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.sling.launchpad.testing</artifactId>
+    <packaging>war</packaging>
+    <version>5-incubator</version>
+
+    <name>Apache Sling Launchpad Testing</name>
+    <description>
+        Sling Launchpad Testing module, contains integration tests that
+        were previously in the launchpad webapp module.
+    </description>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/incubator/sling/tags/org.apache.sling.launchpad.testing-5-incubator</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/incubator/sling/tags/org.apache.sling.launchpad.testing-5-incubator</developerConnection>
+        <url>http://svn.apache.org/viewvc/incubator/sling/tags/org.apache.sling.launchpad.testing-5-incubator</url>
+    </scm>
+
+    <properties>
+        <!--
+            Jetty default port (override with -D)
+        -->
+        <http.port>8888</http.port>
+        
+        <!-- path suffix for HTTP access to Sling -->
+        <http.base.path />
+
+        <!-- path suffix for WebDAV access to the repository -->
+        <webdav.workspace.path />
+
+        <!-- hostname for integration tests -->
+        <test.host>localhost</test.host>
+
+        <!--
+            Disable Jetty webapp rescan (override with -D) 
+        -->
+        <jetty.scan.interval.seconds>0</jetty.scan.interval.seconds>
+
+        <!-- 
+            Sling home directory when starting with jetty:run
+        -->
+        <jetty.sling.home>target/sling</jetty.sling.home>
+
+        <!-- 
+            Defines which tests are for the "integration-testing" phase
+        -->
+        <integration.test.code.path>
+            **/launchpad/webapp/integrationtest
+        </integration.test.code.path>
+
+        <!-- 
+            Set this to true to stop mvn once the integration test Jetty instance is
+            started. Useful to manually test the integration testing webapp.
+        -->
+        <integration.test.wait>false</integration.test.wait>
+        
+        <resources.bundles.path>${project.build.directory}/launchpad-bundles/resources/bundles</resources.bundles.path>
+    </properties>
+
+    <build>
+        <plugins>
+
+            <plugin>
+                <artifactId>maven-clean-plugin</artifactId>
+                <version>2.2</version>
+                <configuration>
+                    <filesets>
+                        <fileset>
+                            <directory>${basedir}</directory>
+                            <includes>
+                                <include>derby.log</include>
+                                <include>cachedir</include>
+                                <include>sling</include>
+                            </includes>
+                        </fileset>
+                    </filesets>
+                </configuration>
+            </plugin>
+            <plugin>
+                 <groupId>org.apache.maven.plugins</groupId>
+                 <artifactId>maven-antrun-plugin</artifactId>
+                 <executions>
+                     <execution>
+                         <id>delete-sling-folder</id>
+                         <phase>package</phase>
+                         <goals>
+                             <goal>run</goal>
+                         </goals>
+                         <configuration>
+                             <tasks>
+                                 <echo>SLING-845 - delete parent sling folder before integration tests</echo>
+                                 <delete dir="../../sling" />
+                             </tasks>
+                        </configuration>
+                     </execution>
+                 </executions>
+             </plugin>
+            <plugin>
+                <groupId>org.mortbay.jetty</groupId>
+                <artifactId>maven-jetty-plugin</artifactId>
+                <configuration>
+                    <contextPath>/</contextPath>
+                    <scanIntervalSeconds>
+                        ${jetty.scan.interval.seconds}
+                    </scanIntervalSeconds>
+
+                    <systemProperties>
+                        <systemProperty>
+                            <name>sling.home</name>
+                            <value>${jetty.sling.home}</value>
+                        </systemProperty>
+                        
+                    </systemProperties>
+
+                    <connectors>
+                        <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
+                            <port>${http.port}</port>
+                            <maxIdleTime>60000</maxIdleTime>
+                        </connector>
+                    </connectors>
+
+                    <!-- 
+                        Use target/... as the webapp source, as we unpack stuff there from the
+                        Sling launcher modules
+                    -->
+                    <webAppSourceDirectory>
+                        target/${artifactId}-${pom.version}
+                    </webAppSourceDirectory>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <!-- Unpack the sling-app launcher for inclusion in the web app -->
+                        <id>unpack-dependencies</id>
+                        <goals>
+                            <goal>unpack-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <includeArtifactIds>
+                                org.apache.sling.launchpad.bundles
+                            </includeArtifactIds>
+                            <includes>
+                                resources/**
+                            </includes>
+                            <excludeTransitive>true</excludeTransitive>
+                            <outputDirectory>
+                                ${project.build.directory}/launchpad-bundles
+                            </outputDirectory>
+                            <overWriteReleases>false</overWriteReleases>
+                            <overWriteSnapshots>
+                                true
+                            </overWriteSnapshots>
+                        </configuration>
+                    </execution>
+                    <!-- Launcher Jar -->                    
+                    <execution>
+                        <id>copy-launcher-jar</id>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.apache.sling</groupId>
+                                    <artifactId>org.apache.sling.launchpad.base</artifactId>
+                                    <version>2.0.4-incubator</version>
+                                </artifactItem>
+                            </artifactItems>
+                            <stripVersion>true</stripVersion>
+                            <excludeTransitive>true</excludeTransitive>
+                            <outputDirectory>
+                                ${project.build.directory}/launchpad-bundles/resources
+                            </outputDirectory>
+                        </configuration>
+                    </execution>
+
+                    <execution>
+                        <!-- 
+                        	Copy additional bundles that must be initially installed to
+                            WEB-INF/resources/bundles/N where N = desired
+                            start level 
+                        -->
+                        <id>copy-bundles-dependencies</id>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>
+                                ${resources.bundles.path}/0
+                            </outputDirectory>
+                            <excludeTransitive>true</excludeTransitive>
+                            <includeArtifactIds>
+                                org.apache.sling.launchpad.test-services
+                            </includeArtifactIds>
+                            <includeScope>
+                                provided
+                            </includeScope>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- 
+              Include sling-app launcher classes and resources, but no Sling 
+              bundles (we want to specify our own versions) 
+            -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <configuration>
+                    <webResources>
+                        <!-- the configuration resources -->
+                        <resource>
+                            <directory>
+                                ${project.build.directory}/launchpad-bundles
+                            </directory>
+                            <targetPath>WEB-INF</targetPath>
+                        </resource>
+                        <!-- Legal stuff -->
+                        <resource>
+                            <directory>${basedir}</directory>
+                            <targetPath>META-INF</targetPath>
+                            <includes>
+                                <include>LICENSE*</include>
+                                <include>NOTICE*</include>
+                                <include>DISCLAIMER</include>
+                            </includes>
+                        </resource>
+                    </webResources>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <systemProperties>
+                        <!-- 
+                            WARNING: make sure these URLs are consistent with the
+                            cargo-maven2-plugin settings: AFAIK Maven does not
+                            expand variables in the <value> element.
+                            And WARNING: these properties are duplicated somewhere in this
+                            POM with slightly different values...there must be a better way. 
+                        -->
+                        <property>
+                            <name>launchpad.http.server.url</name>
+                            <value>
+                                http://${test.host}:${http.port}/${http.base.path}
+                            </value>
+                        </property>
+                        <property>
+                            <name>launchpad.webdav.server.url</name>
+                            <value>
+                                http://${test.host}:${http.port}/${webdav.workspace.path}
+                            </value>
+                        </property>
+                    </systemProperties>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <configuration>
+                  <!-- No javadocs -->
+                    <excludePackageNames>
+                        org.apache.sling
+                    </excludePackageNames>
+                </configuration>
+            </plugin>
+        </plugins>
+    </reporting>
+
+    <profiles>
+        <profile>
+            <!--
+                Run the cargo-based integration tests.
+            -->
+            <id>cargoIntegrationTesting</id>
+            <activation>
+                <property>
+                    <name>!maven.test.skip</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>surefire-integration-test</id>
+                                <phase>integration-test</phase>
+                                <goals>
+                                    <goal>test</goal>
+                                </goals>
+                                <configuration>
+                                    <excludes>
+                                        <exclude>none</exclude>
+                                    </excludes>
+                                    <includes>
+                                        <include>
+                                            ${integration.test.code.path}/**/*Test.java
+                                        </include>
+                                    </includes>
+                                    <systemProperties>
+                                        <!-- 
+                                            WARNING: make sure these URLs are consistent with the
+                                            cargo-maven2-plugin settings: AFAIK Maven does not
+                                            expand variables in the <value> element.
+                                            And WARNING: these properties are duplicated somewhere in this
+                                            POM with slightly different values...there must be a better way. 
+                                        -->
+                                        <property>
+                                            <name>
+                                                launchpad.http.server.url
+                                            </name>
+                                            <value>
+                                                http://${test.host}:${http.port}/${project.build.finalName}
+                                            </value>
+                                        </property>
+                                        <property>
+                                            <name>
+                                                launchpad.webdav.server.url
+                                            </name>
+                                            <value>
+                                                http://${test.host}:${http.port}/${project.build.finalName}/${webdav.workspace.path}
+                                            </value>
+                                        </property>
+                                        
+                                    </systemProperties>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.codehaus.cargo</groupId>
+                        <artifactId>cargo-maven2-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>start-container</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>start</goal>
+                                </goals>
+                            </execution>
+                            <execution>
+                                <id>stop-container</id>
+                                <phase>post-integration-test</phase>
+                                <goals>
+                                    <goal>stop</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                        <configuration>
+                            <wait>${integration.test.wait}</wait>
+                            <container>
+                                <containerId>jetty6x</containerId>
+                                <type>embedded</type>
+                                <systemProperties>
+                                    <sling.home>
+                                        ${basedir}/target/it/sling
+                                    </sling.home>
+                                </systemProperties>
+                            </container>
+                            <configuration>
+                                <home>${project.build.directory}/cargo</home>
+                                <properties>
+                                    <cargo.servlet.port>
+                                        ${http.port}
+                                    </cargo.servlet.port>
+                                    <!-- 
+                                        <cargo.jvmargs>-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=30333,server=y,suspend=y</cargo.jvmargs>
+                                    -->
+                                </properties>
+                            </configuration>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <!--
+                By default, do not run the integration tests in the test phase, as they have
+                no Sling instance to talk to.
+                See README.txt for how to run the integration tests against a running instance
+                of Sling.
+            -->
+            <id>disableIntegrationTestsInTestPhase</id>
+            <activation>
+                <property>
+                    <name>!maven.test.skip</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <excludes>
+                                <exclude>
+                                    ${integration.test.code.path}/**/*.java
+                                </exclude>
+                            </excludes>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>        
+    </profiles>
+
+    <dependencies>
+    
+        <!--  The basic Sling WebApp -->
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.launchpad.base</artifactId>
+            <version>2.0.4-incubator</version>
+            <classifier>webapp</classifier>
+            <type>war</type>
+            <scope>runtime</scope>
+        </dependency>
+        
+        <!-- The basic Sling Bundles -->
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.launchpad.bundles</artifactId>
+            <version>5-incubator</version>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+
+        <!-- JCR Install - needs to be in a profile -->
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>biz.aQute</groupId>
+            <artifactId>bnd</artifactId>
+            <version>0.0.169</version>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Dependencies for the Test Build and Run -->
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.testing</artifactId>
+            <version>2.0.4-incubator</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.servlets.post</artifactId>
+            <version>2.0.2-incubator</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.launchpad.test-services</artifactId>
+            <version>2.0.6-incubator</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>jcl-over-slf4j</artifactId>
+            <version>1.5.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <version>1.5.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/src/main/resources/META-INF/DISCLAIMER b/src/main/resources/META-INF/DISCLAIMER
new file mode 100644
index 0000000..90850c2
--- /dev/null
+++ b/src/main/resources/META-INF/DISCLAIMER
@@ -0,0 +1,7 @@
+Apache Sling is an effort undergoing incubation at The Apache Software Foundation (ASF),
+sponsored by the Apache Jackrabbit PMC. Incubation is required of all newly accepted
+projects until a further review indicates that the infrastructure, communications,
+and decision making process have stabilized in a manner consistent with other
+successful ASF projects. While incubation status is not necessarily a reflection of
+the completeness or stability of the code, it does indicate that the project has yet
+to be fully endorsed by the ASF.
\ No newline at end of file
diff --git a/src/main/resources/META-INF/LICENSE b/src/main/resources/META-INF/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/src/main/resources/META-INF/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
diff --git a/src/main/resources/META-INF/NOTICE b/src/main/resources/META-INF/NOTICE
new file mode 100644
index 0000000..861d0ce
--- /dev/null
+++ b/src/main/resources/META-INF/NOTICE
@@ -0,0 +1,8 @@
+Apache Sling Launchpad Testing
+Copyright 2008-2009 The Apache Software Foundation
+
+Apache Sling is based on source code originally developed 
+by Day Software (http://www.day.com/).
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/CreateNodeTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/CreateNodeTest.java
new file mode 100644
index 0000000..e2f024e
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/CreateNodeTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/** Test creating a Node using the MicroslingIntegrationTestClient */
+public class CreateNodeTest extends HttpTestBase {
+
+    public void testCreateNode() throws IOException {
+        final String url = HTTP_BASE_URL + "/CreateNodeTest_1_" + System.currentTimeMillis();
+
+        // add some properties to the node
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("name1","value1");
+        props.put("name2","value2");
+
+        // POST and get URL of created node
+        String urlOfNewNode = null;
+        try {
+            urlOfNewNode = testClient.createNode(url, props);
+        } catch(IOException ioe) {
+            fail("createNode failed: " + ioe);
+        }
+
+        // get and check URL of created node
+        final GetMethod get = new GetMethod(urlOfNewNode + DEFAULT_EXT);
+        final int status = httpClient.executeMethod(get);
+        assertEquals(urlOfNewNode + " must be accessible after createNode",200,status);
+        final String responseBodyStr = get.getResponseBodyAsString();
+        assertTrue(responseBodyStr.contains("value1"));
+        assertTrue(responseBodyStr.contains("value2"));
+
+        // test default txt and html renderings
+        getContent(urlOfNewNode + DEFAULT_EXT, CONTENT_TYPE_PLAIN);
+        getContent(urlOfNewNode + ".txt", CONTENT_TYPE_PLAIN);
+        getContent(urlOfNewNode + ".html", CONTENT_TYPE_HTML);
+        getContent(urlOfNewNode + ".json", CONTENT_TYPE_JSON);
+        getContent(urlOfNewNode + ".xml", CONTENT_TYPE_XML);
+
+        // And extensions for which we have no renderer fail
+        assertHttpStatus(urlOfNewNode + ".pdf", 403);
+        assertHttpStatus(urlOfNewNode + ".someWeirdExtension", 403);
+    }
+
+    public void testCreateNodeMultipart() throws IOException {
+        final String url = HTTP_BASE_URL + "/CreateNodeTest_2_" + System.currentTimeMillis();
+
+        // add some properties to the node
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("name1","value1B");
+        props.put("name2","value2B");
+
+        // POST and get URL of created node
+        String urlOfNewNode = null;
+        try {
+            urlOfNewNode = testClient.createNode(url, props, null, true);
+        } catch(IOException ioe) {
+            fail("createNode failed: " + ioe);
+        }
+
+        // check node contents (not all renderings - those are tested above)
+        final GetMethod get = new GetMethod(urlOfNewNode + DEFAULT_EXT);
+        final int status = httpClient.executeMethod(get);
+        assertEquals(urlOfNewNode + " must be accessible after createNode",200,status);
+        final String responseBodyStr = get.getResponseBodyAsString();
+        assertTrue(responseBodyStr.contains("value1B"));
+        assertTrue(responseBodyStr.contains("value2B"));
+   }
+
+    public void testCreateNodeWithNodeType() throws IOException {
+        final String url = HTTP_BASE_URL + "/CreateNodeTest_3_" + System.currentTimeMillis();
+
+        // add node type param
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("jcr:primaryType","nt:folder");
+
+        // POST and get URL of created node
+        String urlOfNewNode = null;
+        try {
+            urlOfNewNode = testClient.createNode(url, props);
+        } catch(IOException ioe) {
+            fail("createNode failed: " + ioe);
+        }
+
+        String content = getContent(urlOfNewNode + ".json", CONTENT_TYPE_JSON);
+        assertJavascript("nt:folder", content, "out.println(data['jcr:primaryType'])");
+    }
+
+    public void testCreateNewNodeWithNodeType() throws IOException {
+        final String url = HTTP_BASE_URL + "/CreateNodeTest_4_" + System.currentTimeMillis() + "/*";
+
+        // add node type param
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("jcr:primaryType","nt:folder");
+
+        // POST and get URL of created node
+        String urlOfNewNode = null;
+        try {
+            urlOfNewNode = testClient.createNode(url, props);
+        } catch(IOException ioe) {
+            fail("createNode failed: " + ioe);
+        }
+
+        String content = getContent(urlOfNewNode + ".json", CONTENT_TYPE_JSON);
+        assertJavascript("nt:folder", content, "out.println(data['jcr:primaryType'])");
+    }
+
+    public void testDeepCreateNodeWithNodeType() throws IOException {
+        final String url = HTTP_BASE_URL + "/CreateNodeTest_5_" + System.currentTimeMillis();
+
+        // add node type param
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("jcr:primaryType","nt:folder");
+        props.put("foo/jcr:primaryType","nt:folder");
+        props.put("foo/bar/jcr:primaryType","nt:folder");
+
+        // POST and get URL of created node
+        String urlOfNewNode = null;
+        try {
+            urlOfNewNode = testClient.createNode(url, props);
+        } catch(IOException ioe) {
+            fail("createNode failed: " + ioe);
+        }
+
+        String content = getContent(urlOfNewNode + ".3.json", CONTENT_TYPE_JSON);
+        assertJavascript("nt:folder", content, "out.println(data['jcr:primaryType'])");
+        assertJavascript("nt:folder", content, "out.println(data.foo['jcr:primaryType'])");
+        assertJavascript("nt:folder", content, "out.println(data.foo.bar['jcr:primaryType'])");
+    }
+
+    public void testCreateEmptyNode() throws IOException {
+        final String url = HTTP_BASE_URL + "/CreateNodeTest_6_" + System.currentTimeMillis();
+
+        // add node type param
+        final Map<String,String> props = new HashMap<String,String>();
+
+        // POST and get URL of created node
+        String urlOfNewNode = null;
+        try {
+            urlOfNewNode = testClient.createNode(url, props);
+        } catch(IOException ioe) {
+            fail("createNode failed: " + ioe);
+        }
+
+        // get and check URL of created node
+        final GetMethod get = new GetMethod(urlOfNewNode + DEFAULT_EXT);
+        final int status = httpClient.executeMethod(get);
+        assertEquals(urlOfNewNode + " must be accessible after createNode",200,status);
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/EspLoadTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/EspLoadTest.java
new file mode 100644
index 0000000..9cd446d
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/EspLoadTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/** Test the SLING-428 esp load function */
+public class EspLoadTest extends HttpTestBase {
+    
+    private String basePath;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        basePath = "/" + getClass().getSimpleName() + "_" + System.currentTimeMillis();
+    }
+    
+    public void testNestedInclude() throws Exception {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("scriptToInclude", "included-a.esp");
+        props.put(SLING_RESOURCE_TYPE, getClass().getSimpleName());
+        final TestNode tn = new TestNode(HTTP_BASE_URL + basePath, props);
+        final String subfolder = tn.scriptPath + "/subfolder";
+        testClient.mkdirs(WEBDAV_BASE_URL, subfolder);
+        final String [] toDelete = {
+                uploadTestScript(tn.scriptPath, "esp-load/main.esp", "html.esp"),
+                uploadTestScript(tn.scriptPath, "esp-load/included-a.esp", "included-a.esp"),
+                uploadTestScript(subfolder, 
+                        "esp-load/subfolder/included-b.esp", "included-b.esp")
+        };
+
+        try {
+            final String content = getContent(tn.nodeUrl + ".html", CONTENT_TYPE_HTML);
+            
+            final String [] expectedStringsInOrder = {
+                    "main.esp before load",
+                    "included-a.esp before load",
+                    "included-b.esp",
+                    "included-a.esp after load",
+                    "main.esp after load",
+                    "Here's more from included-a"
+            };
+            
+            int pos = 0;
+            for(String expected : expectedStringsInOrder) {
+                final int newPos = content.indexOf(expected);
+                assertTrue("Content (" + content + ") must contain '" + expected + "'", newPos >= 0);
+                assertTrue("String '" + expected + "' must come after previous expected string", newPos > pos);
+                pos = newPos;
+            }
+        } finally {
+            for(String s : toDelete) {
+                testClient.delete(s);
+            }
+        }
+    }
+    
+    public void testNonExistentInclude() throws Exception {
+        final Map<String,String> props = new HashMap<String,String>();
+        final String badScript = "nonexistent.esp";
+        props.put("scriptToInclude", badScript);
+        props.put(SLING_RESOURCE_TYPE, getClass().getSimpleName());
+        final TestNode tn = new TestNode(HTTP_BASE_URL + basePath, props);
+        final String toDelete = uploadTestScript(tn.scriptPath, "esp-load/main.esp", "html.esp");
+        try {
+            assertHttpStatus(tn.nodeUrl + ".html", HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                    "Including " + badScript + " must fail");
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/FileUploadTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/FileUploadTest.java
new file mode 100644
index 0000000..836c1e9
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/FileUploadTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/** Test uploading files to the Sling repository
+ *  via WebDAV, as a first step towards testing the
+ *  complete content creation and rendering scenario. 
+ */
+public class FileUploadTest extends HttpTestBase {
+    
+    /** This only tests the WebDAV interface. We know it works, so
+     *  we're mostly testing our test code here ;-)
+     */
+    public void testUploadAndDelete() throws IOException {
+        final String testFile = "/integration-test/testfile.txt";
+        final InputStream data = getClass().getResourceAsStream(testFile);
+        try {
+            assertNotNull("Local test file " + testFile + " must be found",data);
+            
+            final String webdavUrl = WEBDAV_BASE_URL + "/FileUploadTest." + System.currentTimeMillis() + ".txt";
+            
+            // Upload a file via WebDAV, verify, delete and verify
+            assertHttpStatus(webdavUrl, 404, "Resource " + webdavUrl + " must not exist before test");
+            int status = testClient.upload(webdavUrl, data);
+            assertEquals("upload must return status code 201",201,status);
+            assertHttpStatus(webdavUrl, 200, "Resource " + webdavUrl + " must exist after upload");
+            testClient.delete(webdavUrl);
+            assertHttpStatus(webdavUrl, 404, "Resource " + webdavUrl + " must not exist anymore after deleting");
+        } finally {
+            if(data!=null) {
+                data.close();
+            }
+        }
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/ForwardTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/ForwardTest.java
new file mode 100644
index 0000000..725e888
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/ForwardTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+
+/** Test the {link ScriptHelper#forward) functionality */
+ public class ForwardTest extends HttpTestBase {
+
+    private String nodeUrlA;
+    private String testTextA;
+    private String nodeUrlB;
+    private String testTextB;
+    private String nodeUrlC;
+    private String nodeUrlD;
+    private String nodeUrlE;
+    private String scriptPath;
+    private String forcedResourceType;
+    private Set<String> toDelete = new HashSet<String>();
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Create the test nodes under a path that's specific to this class to
+        // allow collisions
+        final String url = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "/" + System.currentTimeMillis() + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+        final Map<String,String> props = new HashMap<String,String>();
+
+        // Create two test nodes and store their paths
+        testTextA = "Text A " + System.currentTimeMillis();
+        props.put("text", testTextA);
+        nodeUrlA = testClient.createNode(url, props);
+        String pathToInclude = nodeUrlA.substring(HTTP_BASE_URL.length());
+
+        // Node B stores the path of A, so that the test script can
+        // forward A when rendering B
+        testTextB = "Text B " + System.currentTimeMillis();
+        props.put("text", testTextB);
+        props.put("pathToInclude", pathToInclude);
+        nodeUrlB = testClient.createNode(url, props);
+
+        // Node E is like B but with an extension on the forward path
+        props.put("pathToInclude", pathToInclude + ".html");
+        nodeUrlE = testClient.createNode(url, props);
+
+        // Node C is used for the infinite loop detection test
+        props.remove("pathToInclude");
+        props.put("testInfiniteLoop","true");
+        nodeUrlC = testClient.createNode(url, props);
+
+        // Node D is used for the "force resource type" test
+        forcedResourceType = getClass().getSimpleName() + "/" + System.currentTimeMillis();
+        props.remove("testInfiniteLoop");
+        props.put("forceResourceType", forcedResourceType);
+        props.put("pathToInclude", pathToInclude);
+        nodeUrlD = testClient.createNode(url, props);
+
+        // Script for forced resource type
+        scriptPath = "/apps/" + forcedResourceType;
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+        toDelete.add(uploadTestScript(scriptPath,"forward-forced.esp","html.esp"));
+
+        // The main rendering script goes under /apps in the repository
+        scriptPath = "/apps/nt/unstructured";
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+        toDelete.add(uploadTestScript(scriptPath,"forward-test.esp","html.esp"));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        for(String script : toDelete) {
+            testClient.delete(script);
+        }
+    }
+
+    public void testWithoutForward() throws IOException {
+        final String content = getContent(nodeUrlA + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes ESP marker",content.contains("ESP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextA + "</p>"));
+    }
+
+    public void testWithForward() throws IOException {
+        final String content = getContent(nodeUrlB + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes ESP marker",content.contains("ESP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextA + "</p>"));
+        assertTrue("Text of node A is not included (" + content + ")",!content.contains(testTextB));
+    }
+
+    public void testWithForwardAndExtension() throws IOException {
+        final String content = getContent(nodeUrlE + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes ESP marker",content.contains("ESP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextA + "</p>"));
+        assertTrue("Text of node A is not included (" + content + ")",!content.contains(testTextB));
+    }
+
+    public void testInfiniteLoopDetection() throws IOException {
+        // Node C has a property that causes an infinite include loop,
+        // Sling must indicate the problem in its response
+        final GetMethod get = new GetMethod(nodeUrlC + ".html");
+        httpClient.executeMethod(get);
+        final String content = get.getResponseBodyAsString();
+        assertTrue(
+            "Response contains infinite loop error message",
+            content.contains("org.apache.sling.api.request.RecursionTooDeepException"));
+
+        // TODO: SLING-515, status is 500 when running the tests as part of the maven build
+        // but 200 if running tests against a separate instance started with mvn jetty:run
+        // final int status = get.getStatusCode();
+        // assertEquals("Status is 500 for infinite loop",HttpServletResponse.SC_INTERNAL_SERVER_ERROR, status);
+    }
+
+    public void testForcedResourceType() throws IOException {
+        final String content = getContent(nodeUrlD + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes ESP marker",content.contains("ESP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextA + "</p>"));
+        assertTrue("Text of node A is included (" + content + ")",!content.contains(testTextB));
+        assertTrue("Resource type has been forced (" + content + ")",content.contains("Forced resource type:" + forcedResourceType));
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/GeneratedNodeNameTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/GeneratedNodeNameTest.java
new file mode 100644
index 0000000..03c8dd6
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/GeneratedNodeNameTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test the generation of node names for POST requests to URLS
+ *  ending in / *
+ */
+public class GeneratedNodeNameTest extends HttpTestBase {
+
+    private final String postUrl = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "/" + System.currentTimeMillis() + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+
+    public void testTitle() throws IOException {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("title", "Hello There");
+        final String location = testClient.createNode(postUrl, props);
+        final String expect = "hello_there";
+        assertTrue("Location " + location + " ends with " + expect,location.endsWith(expect));
+    }
+
+    public void testSlingPostNodeNameParam() throws IOException {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put(":name", "MyNodeName");
+        final String location = testClient.createNode(postUrl, props);
+        final String expect = "MyNodeName";
+        assertTrue("Location " + location + " ends with " + expect,location.endsWith(expect));
+    }
+
+    public void testSlingPostNodeNameHintParam() throws IOException {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put(":nameHint", "AnotherNodeName");
+        final String location = testClient.createNode(postUrl, props);
+        final String expect = "AnotherNodeName".toLowerCase();
+        assertTrue("Location " + location + " ends with " + expect,location.endsWith(expect));
+    }
+
+    public void testTitleWithSavePrefix() throws IOException {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("./title", "Hello There 2");
+        props.put("title", "not this one");
+        final String location = testClient.createNode(postUrl, props);
+        final String expect = "hello_there_2";
+        assertTrue("Location " + location + " ends with " + expect,location.endsWith(expect));
+    }
+
+    public void testCollision() throws IOException {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("title", "Hello There");
+
+        // posting twice with the same title must work, and return different locations
+        final String locationA = testClient.createNode(postUrl, props);
+        final String locationB = testClient.createNode(postUrl, props);
+
+        assertFalse("Locations A and B must be different (" + locationA + "," + locationB + ")",
+                locationA.equals(locationB));
+    }
+
+    public void testNoParams() throws IOException {
+        final String location = testClient.createNode(postUrl, null);
+        assertTrue("Location end with a digit",Character.isDigit(location.charAt(location.length() - 1)));
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/GeneratedNodeNameTestStar.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/GeneratedNodeNameTestStar.java
new file mode 100644
index 0000000..ceecf7a
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/GeneratedNodeNameTestStar.java
@@ -0,0 +1,82 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test the generation of node names for POST requests to URLS
+ *  ending in / *
+ */
+public class GeneratedNodeNameTestStar extends HttpTestBase {
+
+    private final String postUrl = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "/" + System.currentTimeMillis() + SlingPostConstants.STAR_CREATE_SUFFIX;
+
+    public void testTitle() throws IOException {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("title", "Hello There");
+        final String location = testClient.createNode(postUrl, props);
+        final String expect = "hello_there";
+        assertTrue("Location " + location + " ends with " + expect,location.endsWith(expect));
+    }
+
+    public void testSlingPostNodeNameParam() throws IOException {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put(":name", "MyNodeName");
+        final String location = testClient.createNode(postUrl, props);
+        final String expect = "MyNodeName";
+        assertTrue("Location " + location + " ends with " + expect,location.endsWith(expect));
+    }
+
+    public void testSlingPostNodeNameHintParam() throws IOException {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put(":nameHint", "AnotherNodeName");
+        final String location = testClient.createNode(postUrl, props);
+        final String expect = "AnotherNodeName".toLowerCase();
+        assertTrue("Location " + location + " ends with " + expect,location.endsWith(expect));
+    }
+
+    public void testTitleWithSavePrefix() throws IOException {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("./title", "Hello There 2");
+        props.put("title", "not this one");
+        final String location = testClient.createNode(postUrl, props);
+        final String expect = "hello_there_2";
+        assertTrue("Location " + location + " ends with " + expect,location.endsWith(expect));
+    }
+
+    public void testCollision() throws IOException {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("title", "Hello There");
+
+        // posting twice with the same title must work, and return different locations
+        final String locationA = testClient.createNode(postUrl, props);
+        final String locationB = testClient.createNode(postUrl, props);
+
+        assertFalse("Locations A and B must be different (" + locationA + "," + locationB + ")",
+                locationA.equals(locationB));
+    }
+
+    public void testNoParams() throws IOException {
+        final String location = testClient.createNode(postUrl, null);
+        assertTrue("Location end with a digit",Character.isDigit(location.charAt(location.length() - 1)));
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/GetStarTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/GetStarTest.java
new file mode 100644
index 0000000..e8475e3
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/GetStarTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+
+/** A GET to *.html and *.json must work even if there is no Node
+ *  at the specified path (SLING-344)
+ */
+public class GetStarTest extends RenderingTestBase {
+    private final String random = getClass().getSimpleName() + String.valueOf(System.currentTimeMillis());
+
+    public void testGetStarHtml() throws IOException {
+        getContent(HTTP_BASE_URL + "/*.html", CONTENT_TYPE_HTML);
+        getContent(HTTP_BASE_URL + "/" + random + "/*.html", CONTENT_TYPE_HTML);
+        getContent(HTTP_BASE_URL + "/" + random + "/" + random + "/*.html", CONTENT_TYPE_HTML);
+        getContent(HTTP_BASE_URL + "/" + random + "/*.someselector.html", CONTENT_TYPE_HTML);
+    }
+
+    public void testGetStarJson() throws IOException {
+        getContent(HTTP_BASE_URL + "/*.json", CONTENT_TYPE_JSON);
+        getContent(HTTP_BASE_URL + "/" + random + "/*.json", CONTENT_TYPE_JSON);
+        getContent(HTTP_BASE_URL + "/" + random + "/*.12.json", CONTENT_TYPE_JSON);
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/GetWithSuffixTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/GetWithSuffixTest.java
new file mode 100644
index 0000000..3cd9e4d
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/GetWithSuffixTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+/** GET requests with a suffix should fail with a 404, otherwise
+ *  we get a lot of extra possible URLs which point to the same
+ *  content.
+ */
+public class GetWithSuffixTest extends RenderingTestBase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // set test values
+        testText = "This is a test " + System.currentTimeMillis();
+
+        // create the test node, under a path that's specific to this class to allow collisions
+        final String url = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "_" + System.currentTimeMillis();
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("text", testText);
+        displayUrl = testClient.createNode(url, props);
+
+        // the rendering script goes under /apps in the repository
+        scriptPath = "/apps/nt/unstructured";
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+    }
+
+    public void testWithExactUrl() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","html.esp");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertTrue("Content includes ESP marker",content.contains("ESP template"));
+            assertTrue("Content contains formatted test text",content.contains("<p>" + testText + "</p>"));
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void testGETScript() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","GET.esp");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertTrue("Content includes ESP marker",content.contains("ESP template"));
+            assertTrue("Content contains formatted test text",content.contains("<p>" + testText + "</p>"));
+
+            final String content2 = getContent(displayUrl + ".txt", CONTENT_TYPE_PLAIN);
+            assertTrue("Content includes ESP marker",content2.contains("ESP template"));
+            assertTrue("Content contains formatted test text",content2.contains("<p>" + testText + "</p>"));
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void testWithExtraPathA() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","txt.esp");
+        try {
+            // expected to be found as resource with ext .txt and suffix
+            final String content = getContent(displayUrl + ".txt/extra.html", CONTENT_TYPE_PLAIN);
+            assertTrue("Content includes ESP marker",content.contains("ESP template"));
+            assertTrue("Content contains formatted test text",content.contains("<p>" + testText + "</p>"));
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    /** behavior seems slightly different if using GET.esp vs. html.esp for the
+     *  script name, verify that both give a 404
+     */
+    public void testWithExtraPathB() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","GET.esp");
+        try {
+            // expected to not be found as dispalyUrl has no dots
+            assertHttpStatus(displayUrl + "/extra/more.a4.html", HttpServletResponse.SC_NOT_FOUND);
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/HttpPingTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/HttpPingTest.java
new file mode 100644
index 0000000..6fc4059
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/HttpPingTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+
+/** Ping the Sling server to verify that our integration test
+ *  setup is ok.
+ */
+public class HttpPingTest extends HttpTestBase {
+    
+    public void testWebServerRoot() throws Exception
+    {
+        // by default, the Launchpad default servlet redirects / to index.html
+        final String url = HTTP_BASE_URL + "/";
+        final GetMethod get = new GetMethod(url);
+        get.setFollowRedirects(false);
+        final int status = httpClient.executeMethod(get);
+        assertEquals("Status must be 302 for " + url, 302, status);
+        final Header h = get.getResponseHeader("Location");
+        assertNotNull("Location header must be provided",h);
+        assertTrue("Location header must end with index.html", h.getValue().endsWith("index.html"));
+    }
+    
+    public void test404() throws Exception
+    {
+        assertHttpStatus(HTTP_BASE_URL + "/someNonExistentUrl", 404);
+    }
+    
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/IncludeTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/IncludeTest.java
new file mode 100644
index 0000000..7326dbf
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/IncludeTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+
+/** Test the {link ScriptHelper#include) functionality */
+ public class IncludeTest extends HttpTestBase {
+
+    private String nodeUrlA;
+    private String testTextA;
+    private String nodeUrlB;
+    private String testTextB;
+    private String nodeUrlC;
+    private String nodeUrlD;
+    private String nodeUrlE;
+    private String scriptPath;
+    private Set<String> toDelete = new HashSet<String>();
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Create the test nodes under a path that's specific to this class to
+        // allow collisions
+        final String url = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "/" + System.currentTimeMillis() + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+        final Map<String,String> props = new HashMap<String,String>();
+
+        // Create two test nodes and store their paths
+        testTextA = "Text A " + System.currentTimeMillis();
+        props.put("text", testTextA);
+        nodeUrlA = testClient.createNode(url, props);
+        String pathToInclude = nodeUrlA.substring(HTTP_BASE_URL.length());
+
+        // Node B stores the path of A, so that the test script can
+        // include A when rendering B
+        testTextB = "Text B " + System.currentTimeMillis();
+        props.put("text", testTextB);
+        props.put("pathToInclude", pathToInclude);
+        nodeUrlB = testClient.createNode(url, props);
+
+        // Node E is like B but with an extension on the include path
+        props.put("pathToInclude", pathToInclude + ".html");
+        nodeUrlE = testClient.createNode(url, props);
+
+        // Node C is used for the infinite loop detection test
+        props.remove("pathToInclude");
+        props.put("testInfiniteLoop","true");
+        nodeUrlC = testClient.createNode(url, props);
+
+        // Node D is used for the "force resource type" test
+        final String forcedResourceType = getClass().getSimpleName() + "/" + System.currentTimeMillis();
+        props.remove("testInfiniteLoop");
+        props.put("forceResourceType", forcedResourceType);
+        props.put("pathToInclude", pathToInclude);
+        nodeUrlD = testClient.createNode(url, props);
+
+        // Script for forced resource type
+        scriptPath = "/apps/" + forcedResourceType;
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+        toDelete.add(uploadTestScript(scriptPath,"include-forced.esp","html.esp"));
+
+        // The main rendering script goes under /apps in the repository
+        scriptPath = "/apps/nt/unstructured";
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+        toDelete.add(uploadTestScript(scriptPath,"include-test.esp","html.esp"));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        for(String script : toDelete) {
+            testClient.delete(script);
+        }
+    }
+
+    public void testWithoutInclude() throws IOException {
+        final String content = getContent(nodeUrlA + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes ESP marker",content.contains("ESP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextA + "</p>"));
+        assertFalse("Nothing has been included",content.contains("<p>Including"));
+    }
+
+    public void testWithInclude() throws IOException {
+        final String content = getContent(nodeUrlB + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes ESP marker",content.contains("ESP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextB + "</p>"));
+        assertTrue("Include has been used",content.contains("<p>Including"));
+        assertTrue("Text of node A is included (" + content + ")",content.contains(testTextA));
+    }
+
+    public void testWithIncludeAndExtension() throws IOException {
+        final String content = getContent(nodeUrlE + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes ESP marker",content.contains("ESP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextB + "</p>"));
+        assertTrue("Include has been used",content.contains("<p>Including"));
+        assertTrue("Text of node A is included (" + content + ")",content.contains(testTextA));
+    }
+
+    public void testInfiniteLoopDetection() throws IOException {
+        // Node C has a property that causes an infinite include loop,
+        // Sling must indicate the problem in its response
+        final GetMethod get = new GetMethod(nodeUrlC + ".html");
+        httpClient.executeMethod(get);
+        final String content = get.getResponseBodyAsString();
+        assertTrue(
+            "Response contains infinite loop error message",
+            content.contains("org.apache.sling.api.request.RecursionTooDeepException"));
+
+        // TODO: SLING-515, status is 500 when running the tests as part of the maven build
+        // but 200 if running tests against a separate instance started with mvn jetty:run
+        // final int status = get.getStatusCode();
+        // assertEquals("Status is 500 for infinite loop",HttpServletResponse.SC_INTERNAL_SERVER_ERROR, status);
+    }
+
+    public void testForcedResourceType() throws IOException {
+        final String content = getContent(nodeUrlD + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes ESP marker",content.contains("ESP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextB + "</p>"));
+        assertTrue("Include has been used",content.contains("<p>Including"));
+        assertTrue("Text of node A is included (" + content + ")",content.contains(testTextA));
+        assertTrue("Resource type has been forced (" + content + ")",content.contains("Forced resource type:" + testTextA));
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/InitialContentTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/InitialContentTest.java
new file mode 100644
index 0000000..a488b7d
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/InitialContentTest.java
@@ -0,0 +1,49 @@
+/* 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+public class InitialContentTest extends HttpTestBase {
+
+    public void testIndex() throws IOException {
+        final String expected = "Do not remove this comment, used for Launchpad integration tests";
+        final String content = getContent(HTTP_BASE_URL + "/index.html", CONTENT_TYPE_HTML);
+        assertTrue("Content contains expected marker (" + content + ")",content.contains(expected));
+    }
+    
+    public void testRootRedirectProperty() throws IOException {
+    	final String expected = "\"sling:resourceType\":\"sling:redirect\"";
+    	final String content = getContent(HTTP_BASE_URL + "/.json", CONTENT_TYPE_JSON);
+    	assertTrue("Content contains " + expected + " (" + content + ")", content.contains(expected));
+    }
+    
+    public void testInitialContentA() throws IOException {
+    	final String expected = "42";
+    	final String content = getContent(
+    			HTTP_BASE_URL + "/sling-test/sling/initial-content-test/marker.txt", CONTENT_TYPE_PLAIN);
+    	assertTrue("Content contains " + expected + " (" + content + ")", content.contains(expected));
+    }
+    
+    public void testInitialContentB() throws IOException {
+    	final String expected = "46";
+    	final String content = getContent(
+    			HTTP_BASE_URL + "/sling-test/initial-content-folder/folder-content-test/marker.txt", CONTENT_TYPE_PLAIN);
+    	assertTrue("Content contains " + expected + " (" + content + ")", content.contains(expected));
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JavascriptWrappersTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JavascriptWrappersTest.java
new file mode 100644
index 0000000..00dc466
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JavascriptWrappersTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/** Test Scriptable objects */
+public class JavascriptWrappersTest extends HttpTestBase {
+
+    private TestNode testRootNode;
+    private String basePath;
+
+    private void createNodes(TestNode n, String prefix, int levels) throws Exception {
+        String url = n.nodeUrl;
+        while(levels >= 1) {
+            url += "/" + prefix + levels;
+            testClient.createNode(url, null);
+            levels--;
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        basePath = "/" + getClass().getSimpleName() + "_" + System.currentTimeMillis();
+
+        final Map<String, String> props = new HashMap<String, String>();
+        props.put(SLING_RESOURCE_TYPE, getClass().getSimpleName());
+        props.put("title", "testnode");
+
+        testRootNode = new TestNode(HTTP_BASE_URL + basePath, props);
+        createNodes(testRootNode, "a", 3);
+        createNodes(testRootNode, "b", 1);
+        createNodes(testRootNode, "c", 2);
+    }
+
+    public void testRecursiveDump() throws IOException {
+        final String toDelete = uploadTestScript(testRootNode.scriptPath, "dump-resource.ecma", "html.ecma");
+        try {
+            final String content = getContent(testRootNode.nodeUrl + ".html", CONTENT_TYPE_HTML);
+
+            final String expected =
+                "1 " + basePath + "/testnode\n"
+                + "2 " + basePath + "/testnode/a3\n"
+                + "3 " + basePath + "/testnode/a3/a2\n"
+                + "4 " + basePath + "/testnode/a3/a2/a1\n"
+                + "2 " + basePath + "/testnode/b1\n"
+                + "2 " + basePath + "/testnode/c2\n"
+                + "3 " + basePath + "/testnode/c2/c1\n"
+                ;
+            assertEquals(expected, content);
+        } finally {
+            testClient.delete(toDelete);
+        }
+
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JsonQueryServletTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JsonQueryServletTest.java
new file mode 100644
index 0000000..eb6c7ce
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JsonQueryServletTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+
+/** Test the {link JsonQueryServlet) functionality. 
+ *  We don't need to test the repository query feature, just
+ *  make sure that the query servlet parameters are interpreted correctly.
+ */
+public class JsonQueryServletTest extends HttpTestBase {
+
+    private String testFolderUrl;
+    private final String testPath = "/" + getClass().getSimpleName() + "_" + System.currentTimeMillis();
+    private final static String counterCode = "out.print(data.length);";
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        
+        testFolderUrl = testClient.createNode(HTTP_BASE_URL + testPath, null);
+        
+        // create subfolders A..E with subnodes 0..4, each contains its name as a text property
+        for(char folder = 'A'; folder <= 'E'; folder++) {
+            final Map<String, String> props = new HashMap<String, String> ();
+            props.put("creator", getClass().getSimpleName());
+            props.put("text", "folder " + folder);
+            final String subfolderUrl = testClient.createNode(testFolderUrl + "/folder" + folder, props);
+            for(int i=0; i < 5; i++) {
+                props.put("text", "folder " + folder + " node "+ i);
+                testClient.createNode(subfolderUrl + "/node" + i, props);
+            }
+            
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        
+        if(testFolderUrl != null) {
+            testClient.delete(WEBDAV_BASE_URL + testPath);
+        }
+    }
+    
+    private void assertCount(int expectedCount, String statement, String queryType, int offset, int rows) 
+    throws IOException {
+        final List<NameValuePair> params = new ArrayList<NameValuePair>();
+        params.add(new NameValuePair("statement", statement));
+        if(queryType != null) {
+            params.add(new NameValuePair("queryType", queryType));
+        }
+        if(offset > 0) {
+            params.add(new NameValuePair("offset", String.valueOf(offset)));
+        }
+        if(rows > 0) {
+            params.add(new NameValuePair("rows", String.valueOf(rows)));
+        }
+        final String json = getContent(testFolderUrl + ".query.json", CONTENT_TYPE_JSON, params);
+        assertJavascript(
+                expectedCount + ".0", 
+                json, 
+                counterCode,
+                "statement=" + statement + ", queryType=" + queryType
+        );
+    }
+    
+    public void testFolderQuery() throws IOException {
+        assertCount(1, "/" + testPath + "/folderC", "xpath", 0, 0);
+    }
+    
+    public void testSubFolderQuery() throws IOException {
+        assertCount(5, "/" + testPath + "/folderA/*", "xpath", 0, 0);
+    }
+    
+    public void testDefaultQueryType() throws IOException {
+        assertCount(5, "/" + testPath + "/folderE/*", null, 0, 0);
+    }
+    
+    public void testSql() throws IOException {
+        final String query = "select * from nt:unstructured where jcr:path like '" + testPath + "/folderB/%'";
+        assertCount(5, query, "sql", 0, 0);
+    }
+    
+    public void testOffset() throws IOException {
+        assertCount(3, "/" + testPath + "/folderC/*", "xpath", 2, 0);
+    }
+    
+    public void testRows() throws IOException {
+        assertCount(2, "/" + testPath + "/folderC/*", "xpath", 0, 2);
+    }
+    
+    public void testPropertyParam() throws IOException {
+        final String url = testFolderUrl + ".query.json";
+        final String statement = "/" + testPath + "/folderB/node3";
+        final List<NameValuePair> params = new ArrayList<NameValuePair>();
+        params.add(new NameValuePair("statement", statement));
+        
+        String json = getContent(url, CONTENT_TYPE_JSON, params);
+        assertJavascript("1.0", json, counterCode);
+        assertJavascript("ok", json, "if(!data[0].text) out.print('ok')");
+        assertJavascript("ok", json, "if(!data[0].creator) out.print('ok')");
+        
+        params.add(new NameValuePair("property", "text"));
+        json = getContent(url, CONTENT_TYPE_JSON, params);
+        assertJavascript("1.0", json, counterCode);
+        assertJavascript("ok", json, "if(data[0].text) out.print('ok')");
+        assertJavascript("folder B node 3", json, "out.print(data[0].text)");
+        assertJavascript("ok", json, "if(!data[0].creator) out.print('ok')");
+        
+        params.add(new NameValuePair("property", "creator"));
+        json = getContent(url, CONTENT_TYPE_JSON, params);
+        assertJavascript("1.0", json, counterCode);
+        assertJavascript("ok", json, "if(data[0].text) out.print('ok')");
+        assertJavascript("folder B node 3", json, "out.print(data[0].text)");
+        assertJavascript("ok", json, "if(data[0].creator) out.print('ok')");
+        assertJavascript(getClass().getSimpleName(), json, "out.print(data[0].creator)");
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JsonRenderingTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JsonRenderingTest.java
new file mode 100644
index 0000000..d20e4a8
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JsonRenderingTest.java
@@ -0,0 +1,228 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test creating Nodes and rendering them in JSON */
+public class JsonRenderingTest extends HttpTestBase {
+
+	private final String testPath = "/" + getClass().getSimpleName();
+    private String postUrl;
+
+    private String testText;
+
+    private String jsonUrl;
+
+    private String createdNodeUrl;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // set test values
+        testText = "This is a test " + System.currentTimeMillis();
+
+        // create the test node, under a path that's specific to this class to
+        // allow collisions
+        postUrl = HTTP_BASE_URL + testPath + "_"
+            + System.currentTimeMillis()
+            + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+        final Map<String, String> props = new HashMap<String, String>();
+        props.put("text", testText);
+        createdNodeUrl = testClient.createNode(postUrl, props);
+        jsonUrl = createdNodeUrl + ".json";
+    }
+
+    /** test our assertJavascript method with static json */
+    public void testAssertJavascript() throws IOException {
+        final String json = "{ 'a' : '123', 'b' : '456' }";
+        assertJavascript("123456", json, "out.println(data.a + data.b)");
+    }
+
+    public void testNonRecursive() throws IOException {
+        final String json = getContent(jsonUrl, CONTENT_TYPE_JSON);
+        assertJavascript(testText, json, "out.println(data.text)");
+    }
+
+    /** Create a node with children, verify that we get them back in JSON format */
+    public void testRecursiveOneLevel() throws IOException {
+        final Map<String, String> props = new HashMap<String, String>();
+        props.put("text", testText);
+
+        final String parentNodeUrl = testClient.createNode(postUrl, props);
+        final String[] children = { "A", "B", "C" };
+        for (String child : children) {
+            props.put("child", child);
+            testClient.createNode(parentNodeUrl + "/" + child, props);
+        }
+
+        final String json = getContent(parentNodeUrl + ".1.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript(testText, json, "out.print(data.text)");
+        for (String child : children) {
+            assertJavascript(child, json, "out.print(data['" + child
+                + "'].child)");
+            assertJavascript(testText, json, "out.print(data['" + child
+                + "'].text)");
+        }
+    }
+
+    /**
+     * Create a node with children, verify that we do not get them back in JSON
+     * format if using recursion level=0
+     */
+    public void testRecursiveZeroLevels() throws IOException {
+        final Map<String, String> props = new HashMap<String, String>();
+        props.put("text", testText);
+
+        final String parentNodeUrl = testClient.createNode(postUrl, props);
+        final String[] children = { "A", "B", "C" };
+        for (String child : children) {
+            props.put("child", child);
+            testClient.createNode(parentNodeUrl + "/" + child, props);
+        }
+
+        // .json and .0.json must both return 0 levels
+        final String[] extensions = { ".json", ".0.json" };
+        for (String extension : extensions) {
+            final String json = getContent(parentNodeUrl + extension,
+                CONTENT_TYPE_JSON);
+            assertJavascript(testText, json, "out.print(data.text)");
+            for (String child : children) {
+                final String testInfo = "extension: " + extension;
+                assertJavascript("undefined", json, "out.print(typeof data['"
+                    + child + "'])", testInfo);
+            }
+        }
+
+    }
+
+    /** Test the "infinity" recursion level */
+    public void testRecursiveInfinity() throws IOException {
+        final Map<String, String> props = new HashMap<String, String>();
+        props.put("text", testText);
+        props.put("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y", "yes");
+        final String url = testClient.createNode(postUrl, props);
+        final String json = getContent(url + ".infinity.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript(testText, json, "out.print(data.text)");
+        assertJavascript("yes", json,
+            "out.print(data.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y)");
+    }
+
+    public void testInvalidLevel() throws IOException {
+        assertHttpStatus(createdNodeUrl + ".notAnIntegerOnPurpose.json",
+            HttpServletResponse.SC_BAD_REQUEST);
+    }
+
+    public void testEscapedStrings() throws IOException {
+        final Map<String, String> props = new HashMap<String, String>();
+        props.put("dq", "Some text with \"double quotes\"");
+        props.put("sq", "Some text with 'single quotes'");
+        props.put("cb", "Some text with {curly brackets}");
+        props.put("sb", "Some text with [square brackets]");
+        props.put("eol", "Some text with end\nof\nlines\nand\ttabs");
+        props.put("html",
+            "Some text with <body class=\"black\" mode=\'none yet\'/> html-like tags");
+        props.put("bs", "Some text with \\backslashes \\here and \\\"there\"");
+
+        final String location = testClient.createNode(postUrl, props);
+        final String json = getContent(location + ".json", CONTENT_TYPE_JSON);
+
+        int counter = 0;
+        for (String key : props.keySet()) {
+            counter++;
+            assertJavascript(props.get(key), json, "out.println(data." + key
+                + ")");
+        }
+    }
+
+    public void testAccentedStrings() throws IOException {
+        final Map<String, String> props = new HashMap<String, String>();
+        props.put("a", "Les amis en \u00E9t\u00E9 au ch\u00E2teau");
+        props.put("b", "The \u00B0 degree sign and \u00F1 ntilde");
+        props.put("c", "The \u0429 cyrillic capital letter shcha");
+        props.put("d", "The \u13C8 cherokee letter qui");
+
+        final String location = testClient.createNode(postUrl, props, null,
+            true);
+        final String json = getContent(location + ".json", CONTENT_TYPE_JSON);
+
+        for (String key : props.keySet()) {
+            assertJavascript(props.get(key), json, "out.println(data." + key
+                + ")");
+        }
+    }
+    
+    protected static int countOccurences(String str, char toCount) {
+    	int result = 0;
+    	for(char c : str.toCharArray()) {
+    		if(c == toCount) {
+    			result++;
+    		}
+    	}
+    	return result;
+    }
+    
+    public void testTidyNonRecursive() throws IOException {
+    	// Count end-of-line chars, there must be more in the tidy form
+    	int noTidyCount = countOccurences(getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON), '\n');
+    	int tidyCount = countOccurences(getContent(createdNodeUrl + ".tidy.json", CONTENT_TYPE_JSON), '\n');
+    	int delta = tidyCount - noTidyCount;
+    	
+    	// Output contains two properties so at least two EOL chars
+    	int min = 2;
+    	
+    	assertTrue("The .tidy selector should add at least 2 EOL chars to json output (delta=" + delta + ")", delta > min);
+    }
+    
+    public void testTidyRecursive() throws IOException {
+        final Map<String, String> props = new HashMap<String, String>();
+        props.put("text", testText);
+        props.put("a/b", "yes");
+        final String url = testClient.createNode(postUrl, props);
+        
+    	int noTidyCount = countOccurences(getContent(url + ".infinity.json", CONTENT_TYPE_JSON), '\n');
+    	int tidyCount = countOccurences(getContent(url + ".tidy.infinity.json", CONTENT_TYPE_JSON), '\n');
+    	int delta = tidyCount - noTidyCount;
+    	
+    	// Output contains 3 properties and a subnode with one, so at least 5 EOL chars
+    	int min = 5;
+    	
+    	assertTrue("The .tidy selector should add at least 2 EOL chars to json output (delta=" + delta + ")", delta > min);
+    }
+    
+    public void testRootNoRecursion() throws IOException {
+    	final String json = getContent(HTTP_BASE_URL + "/.json", CONTENT_TYPE_JSON);
+    	assertJavascript("rep:root", json, "out.print(data['jcr:primaryType'])");
+    	assertJavascript("undefined", json, "out.print(typeof data['jcr:system'])");
+    }
+    
+    public void testRootWithRecursion() throws IOException {
+    	final String json = getContent(HTTP_BASE_URL + "/.1.json", CONTENT_TYPE_JSON);
+    	assertJavascript("rep:root", json, "out.print(data['jcr:primaryType'])");
+    	assertJavascript("rep:system", json, "out.print(data['jcr:system']['jcr:primaryType'])");
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JspForwardTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JspForwardTest.java
new file mode 100644
index 0000000..4c1dc4d
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JspForwardTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+
+/** Test the {link ScriptHelper#forward) functionality */
+ public class JspForwardTest extends HttpTestBase {
+
+    private String nodeUrlA;
+    private String testTextA;
+    private String nodeUrlB;
+    private String testTextB;
+    private String nodeUrlC;
+    private String nodeUrlD;
+    private String nodeUrlE;
+    private String scriptPath;
+    private String forcedResourceType;
+    private Set<String> toDelete = new HashSet<String>();
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Create the test nodes under a path that's specific to this class to
+        // allow collisions
+        final String url = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "/" + System.currentTimeMillis() + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+        final Map<String,String> props = new HashMap<String,String>();
+
+        // Create two test nodes and store their paths
+        testTextA = "Text A " + System.currentTimeMillis();
+        props.put("text", testTextA);
+        nodeUrlA = testClient.createNode(url, props);
+        String pathToInclude = nodeUrlA.substring(HTTP_BASE_URL.length());
+
+        // Node B stores the path of A, so that the test script can
+        // forward A when rendering B
+        testTextB = "Text B " + System.currentTimeMillis();
+        props.put("text", testTextB);
+        props.put("pathToInclude", pathToInclude);
+        nodeUrlB = testClient.createNode(url, props);
+
+        // Node E is like B but with an extension on the forward path
+        props.put("pathToInclude", pathToInclude + ".html");
+        nodeUrlE = testClient.createNode(url, props);
+
+        // Node C is used for the infinite loop detection test
+        props.remove("pathToInclude");
+        props.put("testInfiniteLoop","true");
+        nodeUrlC = testClient.createNode(url, props);
+
+        // Node D is used for the "force resource type" test
+        forcedResourceType = getClass().getSimpleName() + "/" + System.currentTimeMillis();
+        props.remove("testInfiniteLoop");
+        props.put("forceResourceType", forcedResourceType);
+        props.put("pathToInclude", pathToInclude);
+        nodeUrlD = testClient.createNode(url, props);
+
+        // Script for forced resource type
+        scriptPath = "/apps/" + forcedResourceType;
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+        toDelete.add(uploadTestScript(scriptPath,"forward-forced.jsp","html.jsp"));
+
+        // The main rendering script goes under /apps in the repository
+        scriptPath = "/apps/nt/unstructured";
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+        toDelete.add(uploadTestScript(scriptPath,"forward-test.jsp","html.jsp"));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        for(String script : toDelete) {
+            testClient.delete(script);
+        }
+    }
+
+    public void testWithoutForward() throws IOException {
+        final String content = getContent(nodeUrlA + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes JSP marker",content.contains("JSP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextA + "</p>"));
+    }
+
+    public void testWithForward() throws IOException {
+        final String content = getContent(nodeUrlB + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes JSP marker",content.contains("JSP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextA + "</p>"));
+        assertTrue("Text of node A is not included (" + content + ")",!content.contains(testTextB));
+    }
+
+    public void testWithForwardAndExtension() throws IOException {
+        final String content = getContent(nodeUrlE + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes JSP marker",content.contains("JSP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextA + "</p>"));
+        assertTrue("Text of node A is not included (" + content + ")",!content.contains(testTextB));
+    }
+
+    public void testInfiniteLoopDetection() throws IOException {
+        // Node C has a property that causes an infinite include loop,
+        // Sling must indicate the problem in its response
+        final GetMethod get = new GetMethod(nodeUrlC + ".html");
+        httpClient.executeMethod(get);
+        final String content = get.getResponseBodyAsString();
+        assertTrue(
+            "Response contains infinite loop error message",
+            content.contains("org.apache.sling.api.request.RecursionTooDeepException"));
+
+        // TODO: SLING-515, status is 500 when running the tests as part of the maven build
+        // but 200 if running tests against a separate instance started with mvn jetty:run
+        // final int status = get.getStatusCode();
+        // assertEquals("Status is 500 for infinite loop",HttpServletResponse.SC_INTERNAL_SERVER_ERROR, status);
+    }
+
+    public void testForcedResourceType() throws IOException {
+        final String content = getContent(nodeUrlD + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes JSP marker",content.contains("JSP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextA + "</p>"));
+        assertTrue("Text of node A is included (" + content + ")",!content.contains(testTextB));
+        assertTrue("Resource type has been forced (" + content + ")",content.contains("Forced resource type:" + forcedResourceType));
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JspIncludeTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JspIncludeTest.java
new file mode 100644
index 0000000..bce0225
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JspIncludeTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+
+/** Test the {link ScriptHelper#include) functionality */
+ public class JspIncludeTest extends HttpTestBase {
+
+    private String nodeUrlA;
+    private String testTextA;
+    private String nodeUrlB;
+    private String testTextB;
+    private String nodeUrlC;
+    private String nodeUrlD;
+    private String nodeUrlE;
+    private String nodeUrlF;
+    private String scriptPath;
+    private String forcedResourceType;
+    private Set<String> toDelete = new HashSet<String>();
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Create the test nodes under a path that's specific to this class to
+        // allow collisions
+        final String url = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "/" + System.currentTimeMillis() + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+        final Map<String,String> props = new HashMap<String,String>();
+
+        // Create two test nodes and store their paths
+        testTextA = "Text A " + System.currentTimeMillis();
+        props.put("text", testTextA);
+        nodeUrlA = testClient.createNode(url, props);
+        String pathToInclude = nodeUrlA.substring(HTTP_BASE_URL.length());
+
+        // Node B stores the path of A, so that the test script can
+        // include A when rendering B
+        testTextB = "Text B " + System.currentTimeMillis();
+        props.put("text", testTextB);
+        props.put("pathToInclude", pathToInclude);
+        nodeUrlB = testClient.createNode(url, props);
+
+        // Node E is like B but with an extension on the include path
+        props.put("pathToInclude", pathToInclude + ".html");
+        nodeUrlE = testClient.createNode(url, props);
+
+        // Node F is used for the max calls detection test
+        props.put("testMaxCalls","true");
+        nodeUrlF = testClient.createNode(url, props);
+
+        // Node C is used for the infinite loop detection test
+        props.remove("pathToInclude");
+        props.remove("testMaxCalls");
+        props.put("testInfiniteLoop","true");
+        nodeUrlC = testClient.createNode(url, props);
+        
+        // Node D is used for the "force resource type" test
+        forcedResourceType = getClass().getSimpleName() + "/" + System.currentTimeMillis();
+        props.remove("testInfiniteLoop");
+        props.put("forceResourceType", forcedResourceType);
+        props.put("pathToInclude", pathToInclude);
+        nodeUrlD = testClient.createNode(url, props);
+
+        // Script for forced resource type
+        scriptPath = "/apps/" + forcedResourceType;
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+        toDelete.add(uploadTestScript(scriptPath,"include-forced.jsp","html.jsp"));
+
+        // The main rendering script goes under /apps in the repository
+        scriptPath = "/apps/nt/unstructured";
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+        toDelete.add(uploadTestScript(scriptPath,"include-test.jsp","html.jsp"));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        for(String script : toDelete) {
+            testClient.delete(script);
+        }
+    }
+
+    public void testWithoutInclude() throws IOException {
+        final String content = getContent(nodeUrlA + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes JSP marker",content.contains("JSP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextA + "</p>"));
+        assertFalse("Nothing has been included",content.contains("<p>Including"));
+    }
+
+    public void testWithInclude() throws IOException {
+        final String content = getContent(nodeUrlB + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes JSP marker",content.contains("JSP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextB + "</p>"));
+        assertTrue("Include has been used",content.contains("<p>Including"));
+        assertTrue("Text of node A is included (" + content + ")",content.contains(testTextA));
+    }
+
+    public void testWithIncludeAndExtension() throws IOException {
+        final String content = getContent(nodeUrlE + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes JSP marker",content.contains("JSP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextB + "</p>"));
+        assertTrue("Include has been used",content.contains("<p>Including"));
+        assertTrue("Text of node A is included (" + content + ")",content.contains(testTextA));
+    }
+
+    public void testInfiniteLoopDetection() throws IOException {
+        // Node C has a property that causes an infinite include loop,
+        // Sling must indicate the problem in its response
+        final GetMethod get = new GetMethod(nodeUrlC + ".html");
+        httpClient.executeMethod(get);
+        final String content = get.getResponseBodyAsString();
+        assertTrue(
+            "Response contains infinite loop error message",
+            content.contains("org.apache.sling.api.request.RecursionTooDeepException"));
+        
+        // TODO: SLING-515, status is 500 when running the tests as part of the maven build
+        // but 200 if running tests against a separate instance started with mvn jetty:run
+        // final int status = get.getStatusCode();
+        // assertEquals("Status is 500 for infinite loop",HttpServletResponse.SC_INTERNAL_SERVER_ERROR, status);
+    }
+    
+    public void testMaxCallsDetection() throws IOException {
+        // Node F has a property that causes over 1000 includes
+        // Sling must indicate the problem in its response
+        final GetMethod get = new GetMethod(nodeUrlF + ".html");
+        httpClient.executeMethod(get);
+        final String content = get.getResponseBodyAsString();
+        assertTrue(
+            "Response contains infinite loop error message",
+            content.contains("org.apache.sling.api.request.TooManyCallsException"));
+
+        // TODO: SLING-515, status is 500 when running the tests as part of the maven build
+        // but 200 if running tests against a separate instance started with mvn jetty:run
+        // final int status = get.getStatusCode();
+        // assertEquals("Status is 500 for infinite loop",HttpServletResponse.SC_INTERNAL_SERVER_ERROR, status);
+    }
+
+    public void testForcedResourceType() throws IOException {
+        final String content = getContent(nodeUrlD + ".html", CONTENT_TYPE_HTML);
+        assertTrue("Content includes JSP marker",content.contains("JSP template"));
+        assertTrue("Content contains formatted test text",content.contains("<p class=\"main\">" + testTextB + "</p>"));
+        assertTrue("Include has been used",content.contains("<p>Including"));
+        assertTrue("Text of node A is included (" + content + ")",content.contains(testTextA));
+        assertTrue("Resource type has been forced (" + content + ")",content.contains("Forced resource type:" + forcedResourceType));
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JspScriptingTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JspScriptingTest.java
new file mode 100644
index 0000000..449f11f
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/JspScriptingTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test JSP scripting
+ *  TODO this class can be generalized to be used for any scripting language,
+ *  that would help in testing all scripting engines.
+ */
+public class JspScriptingTest extends HttpTestBase {
+ 
+    private String testRootUrl;
+    private TestNode rtNode;
+    private TestNode unstructuredNode;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        
+        final String testRootPath = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "/" + System.currentTimeMillis();
+        testRootUrl = testClient.createNode(testRootPath + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
+        rtNode = new TestNode(testRootPath + "/rt", null);
+        unstructuredNode = new TestNode(testRootPath + "/unstructured", null);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        testClient.delete(testRootUrl);
+        super.tearDown();
+    }
+    
+    public void testRtNoScript() throws Exception {
+        final String content = getContent(rtNode.nodeUrl + ".txt", CONTENT_TYPE_PLAIN);
+        assertTrue(content.contains("PlainTextRendererServlet"));
+        assertTrue("Content contains " + rtNode.testText + " (" + content + ")", content.contains(rtNode.testText));
+    }
+
+    public void testUnstructuredNoScript() throws Exception {
+        final String content = getContent(unstructuredNode.nodeUrl + ".txt", CONTENT_TYPE_PLAIN);
+        assertTrue(content.contains("PlainTextRendererServlet"));
+        assertTrue("Content contains " + unstructuredNode.testText + " (" + content + ")", content.contains(unstructuredNode.testText));
+    }
+    
+    public void testRtJsp() throws Exception {
+        final String toDelete = uploadTestScript(rtNode.scriptPath, "rendering-test.jsp", "html.jsp");
+        try {
+            checkContent(rtNode);
+        } finally {
+            if(toDelete != null) {
+                testClient.delete(toDelete);
+            }
+        }
+    }
+
+    public void testUnstructuredJsp() throws Exception {
+        final String toDelete = uploadTestScript(unstructuredNode.scriptPath, "rendering-test.jsp", "html.jsp");
+        try {
+            checkContent(unstructuredNode);
+        } finally {
+            if(toDelete != null) {
+                testClient.delete(toDelete);
+            }
+        }
+    }
+    
+    private void checkContent(TestNode tn) throws Exception {
+        final String content = getContent(tn.nodeUrl + ".html", CONTENT_TYPE_HTML);
+        assertTrue("JSP script executed as expected (" + content + ")", content.contains("<h1>JSP rendering result</h1>"));
+        
+        final String [] expected = {
+                "using resource.adaptTo:" + tn.testText,
+                "using currentNode:" + tn.testText,
+        };
+        for(String exp : expected) {
+            assertTrue("Content contains " + exp + "(" + content + ")", content.contains(exp));
+        }
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/MkdirTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/MkdirTest.java
new file mode 100644
index 0000000..38ef6af
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/MkdirTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/** Test the MicroslingIntegrationTestClient's mkdir functions */ 
+public class MkdirTest extends HttpTestBase {
+    
+    /** Try creating a directory via WebDAV */
+    public void testMkdir() throws IOException {
+        final String testDirUrl = WEBDAV_BASE_URL + TEST_PATH + System.currentTimeMillis();
+        
+        assertHttpStatus(testDirUrl, 404, testDirUrl);
+        
+        try {
+            testClient.mkdir(testDirUrl);
+        } catch(IOException ioe) {
+            fail(ioe.getMessage());
+        }
+        
+        assertHttpStatus(testDirUrl + DEFAULT_EXT, 200, testDirUrl);
+        
+        try {
+            testClient.mkdir(testDirUrl);
+        } catch(IOException ioe) {
+            fail("mkdir must succeed on an existing directory, got IOException:" + ioe);
+        }
+        
+        assertHttpStatus(testDirUrl + DEFAULT_EXT, 200, testDirUrl);
+        
+        testClient.delete(testDirUrl);
+        assertHttpStatus(testDirUrl, 404, testDirUrl + " must be gone after DELETE");
+    }
+    
+    /** Try creating a deep directory structure */
+    public void testMkdirDeep() throws IOException {
+        final String path = TEST_PATH + "/mkdir-test-" + System.currentTimeMillis() + "/something";
+        final String url = WEBDAV_BASE_URL + path;
+        assertHttpStatus(url,404,url + " must not exist before test");
+        try {
+            testClient.mkdirs(WEBDAV_BASE_URL, path);
+        } catch(IOException ioe) {
+            fail("mkdirs failed:" + ioe);
+        }
+        assertHttpStatus(url + DEFAULT_EXT,200,url + " must exist after test");
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/NodetypeRenderingTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/NodetypeRenderingTest.java
new file mode 100644
index 0000000..7b81d22
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/NodetypeRenderingTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test creating a Node and rendering it using scripts in
+ *  various supported languages, using nodetype-based
+ *  script resolution
+ */
+public class NodetypeRenderingTest extends RenderingTestBase {
+
+    private String secondFolderOfContentPath;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // set test values
+        testText = "This is a test " + System.currentTimeMillis();
+
+        // create the test node, under a path that's specific to this class to allow collisions
+        secondFolderOfContentPath = "" + System.currentTimeMillis();
+        final String url = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "/" + secondFolderOfContentPath + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("text", testText);
+        displayUrl = testClient.createNode(url, props);
+
+        // the rendering script goes under /apps in the repository
+        scriptPath = "/apps/nt/unstructured";
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+    }
+
+    public void testWithoutScriptTxt() throws IOException {
+        final String content = getContent(displayUrl + ".txt", CONTENT_TYPE_PLAIN);
+        assertContains(content, "dumped by PlainTextRendererServlet");
+    }
+
+    public void testWithoutScriptHtml() throws IOException {
+        final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+        assertContains(content, "dumped by HtmlRendererServlet");
+    }
+
+    public void testMiniScriptHtml() throws IOException {
+        final String toDelete = uploadTestScript("no-code.esp","html.esp");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertEquals("There's no code in this script, just this constant string",content);
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+    
+    public void testPrint() throws IOException {
+        final String toDelete = uploadTestScript("print.esp","html.esp");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            final String expected = "print.esp ends";
+            assertContains(content, expected);
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+    
+    public void testEspHtml() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","html.esp");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertContains(content, "ESP template");
+            assertContains(content, "<p>" + testText + "</p>");
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void testEspXml() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","xml.esp");
+        try {
+            final String content = getContent(displayUrl + ".xml", CONTENT_TYPE_XML);
+            assertContains(content, "ESP template");
+            assertContains(content, "<p>" + testText + "</p>");
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void TODO_FAILS_testEspHtmlWithContentBasedPath() throws IOException {
+
+        // make sure there's no leftover rendering script
+        {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertFalse("Content must not include ESP marker before test",content.contains("ESP template"));
+        }
+
+        // put our script in the /apps/<second folder level of content> (SLING-125)
+        final String path = "/apps/" + secondFolderOfContentPath;
+        testClient.mkdirs(WEBDAV_BASE_URL, path);
+        final String toDelete = uploadTestScript(path,"rendering-test.esp","html.esp");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertContains(content, "ESP template");
+            assertContains(content, "<p>" + testText + "</p>");
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void testEspPlain() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","txt.esp");
+        try {
+            final String content = getContent(displayUrl + ".txt", CONTENT_TYPE_PLAIN);
+            assertContains(content, "ESP template");
+            assertContains(content, "<p>" + testText + "</p>");
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void TODO_FAILS_testVltHtml() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.vlt","html.vlt");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertTrue("Content includes VLT marker",content.contains("Velocity template"));
+            assertTrue("Content contains formatted test text",content.contains("<p><b>" + testText + "</b></p>"));
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void TODO_FAILS_testJsHtml() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.ecma","html.ecma");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertTrue("Content includes JS marker",content.contains("Raw javascript template"));
+            assertTrue("Content contains formatted test text",content.contains("<p><em>" + testText + "</em></p>"));
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void TODO_FAILS_testFtlHtml() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.ftl","html.ftl");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertTrue("Content includes FreeMarker marker",content.contains("FreeMarker template"));
+            assertTrue("Content contains formatted test text",content.contains("<p><span>" + testText + "</span></p>"));
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void TODO_FAILS_testErbHtml() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.erb","html.erb");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertTrue("Content includes Ruby marker",content.contains("Ruby template"));
+            assertTrue("Content contains formatted test text",content.contains("<p><span>" + testText + "</span></p>"));
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/PostRedirectTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/PostRedirectTest.java
new file mode 100644
index 0000000..4c88a7d
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/PostRedirectTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test the various redirect options for POST, SLING-126 */
+public class PostRedirectTest extends HttpTestBase {
+
+    private String postPath = "CreateNodeTest/" + System.currentTimeMillis();
+
+    private String postUrl = HTTP_BASE_URL + "/" + postPath
+        + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+
+    public void testForcedRedirect() throws IOException {
+        final Map<String, String> params = new HashMap<String, String>();
+        params.put(":redirect", "http://forced");
+        final Map<String, String> headers = new HashMap<String, String>();
+        headers.put("Referer", "http://referer/");
+
+        final String location = testClient.createNode(postUrl, params, headers,
+            false);
+        assertEquals(
+            "With forced redirect and Referer, redirect must be forced",
+            "http://forced", location);
+    }
+
+    public void testDefaultRedirect() throws IOException {
+        final Map<String, String> params = new HashMap<String, String>();
+        params.put(":redirect", null);
+        final String location = testClient.createNode(postUrl, null, null,
+            false);
+        assertTrue("With no headers or parameters, redirect (" + location
+            + ") must point to created node (path=" + postPath + ")",
+            location.contains(postPath));
+    }
+
+    public void testMagicStarRedirect() throws IOException {
+        final Map<String, String> params = new HashMap<String, String>();
+        params.put(":redirect", "*");
+        final Map<String, String> headers = new HashMap<String, String>();
+        headers.put("Referer", "http://referer/");
+        final String location = testClient.createNode(postUrl, params, headers,
+            false);
+        assertTrue("With magic star, redirect (" + location
+            + ") must point to created node (path=" + postPath + ")",
+            location.contains(postPath));
+    }
+
+    public void testMagicStarRedirectPrefix() throws IOException {
+        String prefix = "xyz/";
+        final Map<String, String> params = new HashMap<String, String>();
+        params.put(":redirect", prefix + "*");
+        final Map<String, String> headers = new HashMap<String, String>();
+        headers.put("Referer", "http://referer/");
+        final String location = testClient.createNode(postUrl, params, headers,
+            false);
+        assertTrue("With magic star, redirect (" + location
+            + ") must start with prefix " + prefix, location.contains(prefix));
+    }
+
+    public void testMagicStarRedirectSuffix() throws IOException {
+        String suffix = "/xyz.html";
+        final Map<String, String> params = new HashMap<String, String>();
+        params.put(":redirect", "*" + suffix);
+        final Map<String, String> headers = new HashMap<String, String>();
+        headers.put("Referer", "http://referer/");
+        final String location = testClient.createNode(postUrl, params, headers,
+            false);
+        assertTrue("With magic star, redirect (" + location
+            + ") must end with suffix " + suffix, location.endsWith(suffix));
+    }
+
+    public void testMagicStarRedirectPrefixSuffix() throws IOException {
+        String prefix = "xyz/";
+        String suffix = "/xyz.html";
+        final Map<String, String> params = new HashMap<String, String>();
+        params.put(":redirect", prefix + "*" + suffix);
+        final Map<String, String> headers = new HashMap<String, String>();
+        headers.put("Referer", "http://referer/");
+        final String location = testClient.createNode(postUrl, params, headers,
+            false);
+        assertTrue("With magic star, redirect (" + location
+            + ") must start with prefix " + prefix + " and end with suffix "
+            + suffix, location.contains(prefix) && location.endsWith(suffix));
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/PropertyRenderingTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/PropertyRenderingTest.java
new file mode 100644
index 0000000..438ff07
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/PropertyRenderingTest.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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test the rendering of JCR Properties, directly addressed by URLs.
+ *  See SLING-133
+ */
+public class PropertyRenderingTest extends RenderingTestBase {
+
+    private String slingResourceType;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // set test values
+        testText = "This is a test " + System.currentTimeMillis();
+        slingResourceType = getClass().getName();
+
+        // create the test node, under a path that's specific to this class to allow collisions
+        final String url = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "/" + System.currentTimeMillis() + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("sling:resourceType", slingResourceType);
+        props.put("text", testText);
+        displayUrl = testClient.createNode(url, props);
+    }
+
+    public void testNodeAccess() throws IOException {
+        final String json = getContent(displayUrl + ".json", CONTENT_TYPE_JSON);
+        assertJavascript(testText, json, "out.println(data.text)");
+    }
+
+    public void testTextJson() throws IOException {
+        final String json = getContent(displayUrl + "/text.json", CONTENT_TYPE_JSON);
+        assertEquals("{\"text\":\"" + testText + "\"}",json);
+    }
+
+    public void testTextHtml() throws IOException {
+        final String data = getContent(displayUrl + "/text.html", CONTENT_TYPE_HTML);
+        assertTrue(data.contains(testText));
+    }
+
+    public void testTextTxt() throws IOException {
+        final String data = getContent(displayUrl + "/text.txt", CONTENT_TYPE_PLAIN);
+        assertEquals(testText, data);
+    }
+
+    public void testTextNoExt() throws IOException {
+        final String data = getContent(displayUrl + "/text", null);
+        assertEquals(testText, data);
+    }
+
+    public void testResourceTypeNoExt() throws IOException {
+        final String data = getContent(displayUrl + "/sling:resourceType", null);
+        assertEquals(slingResourceType, data);
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/RedirectTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/RedirectTest.java
new file mode 100644
index 0000000..38d78cd
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/RedirectTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test creating Nodes and rendering them in JSON */
+public class RedirectTest extends HttpTestBase {
+
+    private String postUrl;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // create the test node, under a path that's specific to this class to
+        // allow collisions
+        postUrl = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "_"
+            + System.currentTimeMillis()
+            + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+    }
+
+    /** test 302 response with existing sling:target */
+    public void testRedirect302() throws IOException {
+
+        // create a node redirecting to /index
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("sling:resourceType", "sling:redirect");
+        props.put("sling:target", "/index.html");
+        String redirNodeUrl = testClient.createNode(postUrl, props);
+
+        // get the created node without following redirects
+        GetMethod get = new GetMethod(redirNodeUrl);
+        get.setFollowRedirects(false);
+        int status = httpClient.executeMethod(get);
+
+        // expect temporary redirect ...
+        assertEquals(302, status);
+
+        // ... to */index.html
+        String location = get.getResponseHeader("Location").getValue();
+        assertNotNull(location);
+        assertTrue(location.endsWith("/index.html"));
+
+        // get the created node without following redirects
+        get = new GetMethod(redirNodeUrl + ".html");
+        get.setFollowRedirects(false);
+        status = httpClient.executeMethod(get);
+
+        // expect temporary redirect ...
+        assertEquals(302, status);
+
+        // ... to */index.html
+        location = get.getResponseHeader("Location").getValue();
+        assertNotNull(location);
+        assertTrue(location.endsWith("/index.html.html"));
+    }
+
+    /** test 404 response when sling:target is missing */
+    public void testRedirect404() throws IOException {
+        // create a sling:redirect node without a target
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("sling:resourceType", "sling:redirect");
+        String redirNodeUrl = testClient.createNode(postUrl, props);
+
+        // get the created node without following redirects
+        GetMethod get = new GetMethod(redirNodeUrl);
+        get.setFollowRedirects(false);
+        int status = httpClient.executeMethod(get);
+
+        // expect 404 not found
+        assertEquals(404, status);
+
+        // get the created node without following redirects
+        get = new GetMethod(redirNodeUrl + ".html");
+        get.setFollowRedirects(false);
+        status = httpClient.executeMethod(get);
+
+        // expect 404 not found
+        assertEquals(404, status);
+    }
+
+    /** test JSON result for .json requests with sling:target */
+    public void testRedirectJson() throws JSONException, IOException {
+        // create a sling:redirect node without a target
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("sling:resourceType", "sling:redirect");
+        props.put("sling:target", "/index.html");
+        String redirNodeUrl = testClient.createNode(postUrl, props);
+
+        // get the created node without following redirects
+        final GetMethod get = new GetMethod(redirNodeUrl + ".json");
+        get.setFollowRedirects(false);
+        final int status = httpClient.executeMethod(get);
+
+        // expect 200 OK with the JSON data
+        assertEquals(200, status);
+        assertTrue(get.getResponseHeader("Content-Type").getValue().startsWith(CONTENT_TYPE_JSON));
+
+        // the json data
+        String jsonString = get.getResponseBodyAsString();
+        JSONObject json = new JSONObject(jsonString);
+
+        assertEquals("sling:redirect", json.get("sling:resourceType"));
+        assertEquals("/index.html", json.get("sling:target"));
+    }
+
+    /** test JSON result for .json requests with sling:target */
+    public void testRedirectJson2() throws JSONException, IOException {
+        // create a sling:redirect node without a target
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("sling:resourceType", "sling:redirect");
+        String redirNodeUrl = testClient.createNode(postUrl, props);
+
+        // get the created node without following redirects
+        final GetMethod get = new GetMethod(redirNodeUrl + ".json");
+        get.setFollowRedirects(false);
+        final int status = httpClient.executeMethod(get);
+
+        // expect 200 OK with the JSON data
+        assertEquals(200, status);
+        assertTrue(get.getResponseHeader("Content-Type").getValue().startsWith(CONTENT_TYPE_JSON));
+
+        // the json data
+        String jsonString = get.getResponseBodyAsString();
+        JSONObject json = new JSONObject(jsonString);
+
+        assertEquals("sling:redirect", json.get("sling:resourceType"));
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/RenderingTestBase.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/RenderingTestBase.java
new file mode 100644
index 0000000..6fa6ea8
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/RenderingTestBase.java
@@ -0,0 +1,39 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/** Base class for rendering tests
+ */
+class RenderingTestBase extends HttpTestBase {
+    protected String scriptPath;
+    protected String testText;
+    protected String displayUrl;
+    
+    protected String uploadTestScript(String localFilename,String filenameOnServer) throws IOException {
+        return uploadTestScript(scriptPath, localFilename, filenameOnServer);
+    }
+    
+    protected void assertContains(String content, String expected) {
+        if(!content.contains(expected)) {
+            fail("Content does not contain '" + expected + "' (content=" + content + ")");
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/RequestAttributeTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/RequestAttributeTest.java
new file mode 100644
index 0000000..41800f5
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/RequestAttributeTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.ByteArrayInputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/**
+ * Test the "org.apache.sling.api.include.servlet" and
+ * "org.apache.sling.api.include.resource" request attributes with the {link
+ * ScriptHelper#include) functionality
+ */
+public class RequestAttributeTest extends HttpTestBase {
+
+    private String nodeUrlA;
+
+    private String nodeUrlB;
+
+    private String scriptPath;
+
+    private Set<String> toDelete = new HashSet<String>();
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Create the test nodes under a path that's specific to this class to
+        // allow collisions
+        final String url = HTTP_BASE_URL + "/" + getClass().getSimpleName()
+            + "/" + System.currentTimeMillis()
+            + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+        final Map<String, String> props = new HashMap<String, String>();
+
+        // Create two test nodes and store their paths
+        props.put("text", "texta");
+        props.put("jcr:primaryType", "nt:unstructured");
+        nodeUrlA = testClient.createNode(url, props);
+
+        props.clear();
+        props.put("text", "textb");
+        props.put("jcr:primaryType", "nt:unstructured");
+        nodeUrlB = testClient.createNode(nodeUrlA + "/child", props);
+
+        // The main rendering script goes under /apps in the repository
+        scriptPath = "/apps/nt/unstructured";
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+        toDelete.add(uploadTestScript(scriptPath, "request-attribute-test.esp",
+            "txt.esp"));
+        toDelete.add(uploadTestScript(scriptPath,
+            "request-attribute-test-sel1.esp", "sel1.txt.esp"));
+        toDelete.add(uploadTestScript(scriptPath,
+            "request-attribute-test-sel2.esp", "sel2.txt.esp"));
+        toDelete.add(uploadTestScript(scriptPath,
+            "request-attribute-test-sel3.esp", "sel3.txt.esp"));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        for (String script : toDelete) {
+            testClient.delete(script);
+        }
+        super.tearDown();
+    }
+
+    public void testRequestAttribute() throws Exception {
+        final String content = getContent(nodeUrlA + ".txt", CONTENT_TYPE_PLAIN);
+
+        final Properties props = new Properties();
+        props.load(new ByteArrayInputStream(content.getBytes("ISO-8859-1")));
+
+        final String pA = new URL(nodeUrlA).getPath();
+        final String pB = new URL(nodeUrlB).getPath();
+
+        // this is from txt.esp
+        assertEquals("Request Servlet 0 is null", "null",
+            props.get("servlet00"));
+        assertEquals("Request Resource 0 is null", "null",
+            props.get("resource00"));
+        assertEquals("Request Servlet 1 is null", "null",
+            props.get("servlet01"));
+        assertEquals("Request Resource 1 is null", "null",
+            props.get("resource01"));
+
+        // this is from sel1.txt.esp, included by txt.esp
+        assertEquals("Request Servlet 10", "/apps/nt/unstructured/txt.esp",
+            props.get("servlet10"));
+        assertEquals("Request Resource 10", pA, props.get("resource10"));
+        assertEquals("Request Servlet 11", "/apps/nt/unstructured/txt.esp",
+            props.get("servlet11"));
+        assertEquals("Request Resource 11", pA, props.get("resource11"));
+
+        // this is from sel2.txt.esp, included by txt.esp
+        assertEquals("Request Servlet 20", "/apps/nt/unstructured/txt.esp",
+            props.get("servlet20"));
+        assertEquals("Request Resource 20", pA, props.get("resource20"));
+
+        // this is from sel3.txt.esp, included by sel1.txt.esp
+        assertEquals("Request Servlet 30",
+            "/apps/nt/unstructured/sel1.txt.esp", props.get("servlet30"));
+        assertEquals("Request Resource 30", pB, props.get("resource30"));
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/ScriptBuiltinObjectsTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/ScriptBuiltinObjectsTest.java
new file mode 100644
index 0000000..8651f57
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/ScriptBuiltinObjectsTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+public class ScriptBuiltinObjectsTest extends RenderingTestBase {
+
+    private String slingResourceType;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // set test values
+        slingResourceType = "integration-test/srt." + System.currentTimeMillis();
+        testText = "This is a test " + System.currentTimeMillis();
+
+        // create the test node, under a path that's specific to this class to allow collisions
+        final String url = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "/" + System.currentTimeMillis() + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("sling:resourceType", slingResourceType);
+        props.put("text", testText);
+        displayUrl = testClient.createNode(url, props);
+
+        // the rendering script goes under /apps in the repository
+        scriptPath = "/apps/" + slingResourceType;
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+    }
+
+    public void testEspBuiltinObjects() throws IOException {
+        final String toDelete = uploadTestScript("builtin-objects.esp","html.esp");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertTrue("Content includes ESP marker (" + content + ")",content.contains("ESP template"));
+            assertTrue("Content includes test text (" + content + ")", content.contains(testText));
+            assertTrue("Content includes currentNode text (" + content + ")", content.contains("currentNode.text:" + testText));
+            assertTrue("Content includes sc data (" + content + ")",content.contains("sc:null"));
+            assertTrue("Content includes response data (" + content + ")",content.contains("SlingHttpServletResponse:false"));
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/SlingResourceTypeRenderingTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/SlingResourceTypeRenderingTest.java
new file mode 100644
index 0000000..73aeea3
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/SlingResourceTypeRenderingTest.java
@@ -0,0 +1,225 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test creating a Node and rendering it using scripts in
+ *  various supported languages, using slingResourceType-based
+ *  script resolution
+ */
+public class SlingResourceTypeRenderingTest extends RenderingTestBase {
+
+    private String slingResourceType;
+    private String secondFolderOfContentPath;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // set test values
+        slingResourceType = "integration-test/srt." + System.currentTimeMillis();
+        testText = "This is a test " + System.currentTimeMillis();
+
+        // create the test node, under a path that's specific to this class to allow collisions
+        secondFolderOfContentPath = "" + System.currentTimeMillis();
+        final String url = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "/" + secondFolderOfContentPath + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("sling:resourceType", slingResourceType);
+        props.put("text", testText);
+        displayUrl = testClient.createNode(url, props);
+
+        // the rendering script goes under /apps in the repository
+        scriptPath = "/apps/" + slingResourceType;
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+    }
+
+    public void testWithoutScriptTxt() throws IOException {
+        final String content = getContent(displayUrl + ".txt", CONTENT_TYPE_PLAIN);
+        assertContains(content, "dumped by PlainTextRendererServlet");
+    }
+
+    public void testWithoutScriptHtml() throws IOException {
+        final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+        assertContains(content, "dumped by HtmlRendererServlet");
+    }
+
+    public void testEspHtml() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","html.esp");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertContains(content, "ESP template");
+            assertContains(content, "<p>" + testText + "</p>");
+            assertContains(content, "<div class=\"SLING-142\" id=\"22\"/>");
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void testEspJavaCode() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","html.esp");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertContains(content, "ESP template");
+            assertContains(content, "TestLinkedListTest");
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void testEspHtmlInAppsFolder() throws IOException {
+        // make sure there's no leftover rendering script
+        {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertFalse("Content must not contain script marker before testing", content.contains("ESP template"));
+        }
+
+        // put our script under /apps/<resource type>
+        final String path = "/apps/" + slingResourceType;
+        testClient.mkdirs(WEBDAV_BASE_URL, path);
+        final String toDelete = uploadTestScript(path,"rendering-test.esp","html.esp");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertContains(content, "ESP template");
+            assertContains(content, "<p>" + testText + "</p>");
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void TODO_FAILS_testEspHtmlWithContentBasedPath() throws IOException {
+
+        // make sure there's no leftover rendering script
+        {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertContains(content, "ESP template");
+        }
+
+        // put our script in the /apps/<second folder level of content> (SLING-125)
+        final String path = "/apps/" + secondFolderOfContentPath;
+        testClient.mkdirs(WEBDAV_BASE_URL, path);
+        final String toDelete = uploadTestScript(path,"rendering-test.esp","html.esp");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertContains(content, "ESP template");
+            assertContains(content, "<p>" + testText + "</p>");
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void testEspHtmlWithSelectors() throws IOException {
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath + "/a4");
+        final String toDeleteA = uploadTestScript("rendering-test.esp","html.esp");
+        final String toDeleteB = uploadTestScript("rendering-test-2.esp","a4.esp");
+        final String toDeleteC = uploadTestScript("rendering-test-3.esp","a4/print.esp");
+
+        try {
+            String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertTrue("Without selectors, content includes standard marker",content.contains("ESP template"));
+            assertTrue("Without selectors, content contains formatted test text",content.contains("<p>" + testText + "</p>"));
+
+            content = getContent(displayUrl + ".a4.print.html", CONTENT_TYPE_HTML);
+            assertTrue("With a4.print selectors, content includes marker 3",content.contains("Template #3 for ESP tests"));
+            assertTrue("With a4.print selectors, content contains italic text",content.contains("<em>" + testText + "</em>"));
+
+            content = getContent(displayUrl + ".a4.html", CONTENT_TYPE_HTML);
+            assertTrue("With a4 selector, content includes marker 2",content.contains("Template #2 for ESP tests"));
+            assertTrue("With a4 selector, content contains bold text",content.contains("<b>" + testText + "</b>"));
+
+            content = getContent(displayUrl + ".different.html", CONTENT_TYPE_HTML);
+            assertTrue("With different selector only, content includes standard marker",content.contains("ESP template"));
+            assertTrue("With different selector only, content contains formatted test text",content.contains("<p>" + testText + "</p>"));
+        } finally {
+            testClient.delete(toDeleteA);
+            testClient.delete(toDeleteB);
+            testClient.delete(toDeleteC);
+        }
+    }
+
+    public void TODO_FAILS_testEspHtmlUppercase() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","html.esp");
+        try {
+            final String content = getContent(displayUrl + ".HTML", CONTENT_TYPE_HTML);
+            assertTrue("Content includes ESP marker",content.contains("ESP template"));
+            assertTrue("Content contains formatted test text",content.contains("<p>" + testText + "</p>"));
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void TODO_FAILS_testEspNoExtension() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","GET.esp");
+        try {
+            final String content = getContent(displayUrl, CONTENT_TYPE_PLAIN);
+            assertTrue("Content includes ESP marker",content.contains("ESP template"));
+            assertTrue("Content contains formatted test text",content.contains("<p>" + testText + "</p>"));
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    /** SLING-107, verify that extension is used instead of Content-Type for script name */
+    public void testEspJs() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","js.esp");
+        try {
+            final String content = getContent(displayUrl + ".js", CONTENT_TYPE_JS);
+            // template makes no JS sense, that's not a problem for this test
+            assertContains(content, "ESP template");
+            assertContains(content, "<p>" + testText + "</p>");
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void testEspXml() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","xml.esp");
+        try {
+            final String content = getContent(displayUrl + ".xml", CONTENT_TYPE_XML);
+            assertContains(content, "ESP template");
+            assertContains(content, "<p>" + testText + "</p>");
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void testEspPlain() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.esp","txt.esp");
+        try {
+            final String content = getContent(displayUrl + ".txt", CONTENT_TYPE_PLAIN);
+            assertContains(content, "ESP template");
+            assertContains(content, "<p>" + testText + "</p>");
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+    public void TODO_FAILS_testJsHtml() throws IOException {
+        final String toDelete = uploadTestScript("rendering-test.ecma","html.ecma");
+        try {
+            final String content = getContent(displayUrl + ".html", CONTENT_TYPE_HTML);
+            assertTrue("Content includes JS marker",content.contains("Raw javascript template"));
+            assertTrue("Content contains formatted test text",content.contains("<p><em>" + testText + "</em></p>"));
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/StaticContentTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/StaticContentTest.java
new file mode 100644
index 0000000..77adde7
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/StaticContentTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/** Some tests about static content */
+public class StaticContentTest extends HttpTestBase {
+    
+    public void testWebInfForbidden() throws IOException {
+        // if DefaultSlingServlet handled this we'd get an SC_FORBIDDEN, but it looks
+        // like the servlet container blocks it already
+        assertHttpStatus(HTTP_BASE_URL + "/WEB-INF/web.xml", HttpServletResponse.SC_NOT_FOUND);
+    }
+    
+    public void testMetaInfForbidden() throws IOException {
+        // if DefaultSlingServlet handled this we'd get an SC_FORBIDDEN, but it looks
+        // like the servlet container blocks it already
+        assertHttpStatus(HTTP_BASE_URL + "/META-INF/somefile.txt", HttpServletResponse.SC_NOT_FOUND);
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/StreamServletTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/StreamServletTest.java
new file mode 100644
index 0000000..120f840
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/StreamServletTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+
+/** Test the streaming of static files uploaded to the repository */
+public class StreamServletTest extends RenderingTestBase {
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        scriptPath = TEST_PATH + "/StreamServletTest." + System.currentTimeMillis();
+        displayUrl = HTTP_BASE_URL + scriptPath;
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+    }
+    
+    private void runTest(String filename, String expectedContentType, String expectedContent) throws Exception {
+        final String toDelete = uploadTestScript(filename,filename);
+        try {
+            final String url = displayUrl + "/" + filename;
+            final String content = getContent(url, expectedContentType);
+            assertEquals(expectedContent, content);
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+    
+    public void testPlainTextFile() throws Exception {
+        runTest("testfile.txt", CONTENT_TYPE_PLAIN, "This is just some text in an ASCII file.");
+    }
+
+    public void testHtmlFile() throws Exception {
+        runTest("testfile.html", CONTENT_TYPE_HTML, "This is <em>testfile.html</em>");
+    }
+    
+    public void testJavascriptFile() throws Exception {
+        runTest("testfile.js", CONTENT_TYPE_JS, "// This is testfile.js");
+    }
+    
+    public void testJsonFile() throws Exception {
+        runTest("testfile.json", CONTENT_TYPE_JSON, "This is testfile.json");
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/SyntheticResourceTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/SyntheticResourceTest.java
new file mode 100644
index 0000000..d46f2d7
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/SyntheticResourceTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+
+/** Test the SLING-129 {@link org.apache.sling.api.resource.SyntheticResource}, by requesting
+ *  non-existent Nodes..
+ */
+public class SyntheticResourceTest extends HttpTestBase {
+
+    /** recurse random URLs under basePath, going nLevels deep,
+     *  and check that we get the specified status for every URL
+     * @throws IOException
+     */
+    private void assertDeepGetStatus(String basePath, int nLevels, int expectedStatus, String urlSuffix) throws IOException {
+        String path = basePath;
+        for(int level=1; level <= nLevels; level++) {
+            final String url = HTTP_BASE_URL + path + urlSuffix;
+            assertHttpStatus(url, expectedStatus,"Unexpected status at URL=" + url);
+            basePath += "/level_" + level + "_" + (int)(Math.random() * Integer.MAX_VALUE);
+        }
+    }
+
+    public void TODO_FAILS_testSearchSyntheticResource() throws IOException {
+        // build a very random deep URL under /search and
+        // verify that we get a 200 every time
+        assertDeepGetStatus("/search",10,200,"");
+    }
+
+    public void TODO_FAILS_testSearchSyntheticResourceHtml() throws IOException {
+        // build a very random deep URL under /search and
+        // verify that we get a 200 every time
+        assertDeepGetStatus("/search",10,200,".html");
+        assertDeepGetStatus("/search",10,200,".a4.print.html");
+    }
+
+    public void TODO_FAILS_testSearchSyntheticResourceJson() throws IOException {
+        // build a very random deep URL under /search and
+        // verify that we get a 200 every time
+        assertDeepGetStatus("/search",10,200,".json");
+        assertDeepGetStatus("/search",10,200,".a4.print.json");
+    }
+
+    public void TODO_FAILS_testSearchSyntheticResourceTxt() throws IOException {
+        // build a very random deep URL under /search and
+        // verify that we get a 200 every time
+        assertDeepGetStatus("/search",10,200,".txt");
+        assertDeepGetStatus("/search",10,200,".a4.print.txt");
+    }
+
+    public void testNoSyntheticResourceTest() throws IOException {
+        // walk down a random path, verify that we
+        // get 404s all the time
+        final String basePath = "/" + getClass().getSimpleName() + "_" + System.currentTimeMillis() + "/" + (int)(Math.random() * Integer.MAX_VALUE);
+        assertDeepGetStatus(basePath,10,404,"");
+    }
+
+    public void TODO_FAILS_testSyntheticResourceWithJstTemplate() throws IOException {
+        final String synthResourceUrl = HTTP_BASE_URL + "/search/something.SyntheticResourceTest.html";
+        {
+            final String content = getContent(synthResourceUrl, CONTENT_TYPE_HTML);
+            assertFalse("Content must not include JST marker before test",content.contains("JST template"));
+        }
+
+        //final String scriptPath = "/apps/" + SyntheticResource.DEFAULT_RESOURCE_TYPE + "/SyntheticResourceTest";
+        final String scriptPath = "TODO";
+        testClient.mkdirs(WEBDAV_BASE_URL, scriptPath);
+        final String toDelete = uploadTestScript(scriptPath,"rendering-test.jst","html.jst");
+        try {
+            final String content = getContent(synthResourceUrl, CONTENT_TYPE_HTML);
+            assertTrue("Content includes JST marker: " + content,content.contains("JST template"));
+        } finally {
+            testClient.delete(toDelete);
+        }
+    }
+
+
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/UploadFileTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/UploadFileTest.java
new file mode 100644
index 0000000..bb5dc74
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/UploadFileTest.java
@@ -0,0 +1,215 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/**
+ * Test uploading files using the Sling post servlet (SLING-168)
+ */
+public class UploadFileTest extends HttpTestBase {
+
+    private static final String TEST_FILE = "src/test/resources/integration-test/file-to-upload.txt";
+
+    public void testDistinctResource() throws IOException {
+        String folderPath = "/UploadFileTest_1_" + System.currentTimeMillis();
+        final String url = HTTP_BASE_URL + folderPath;
+
+        // create new node
+        String urlOfNewNode = null;
+        try {
+            urlOfNewNode = testClient.createNode(url, null);
+        } catch(IOException ioe) {
+            fail("createNode failed: " + ioe);
+        }
+
+        // upload local file
+        File localFile = new File(TEST_FILE);
+        testClient.uploadToFileNode(urlOfNewNode, localFile, "./file", null);
+
+        // get and check URL of created file
+        String urlOfFileNode = urlOfNewNode + "/file";
+        final GetMethod get = new GetMethod(urlOfFileNode);
+        final int status = httpClient.executeMethod(get);
+        assertEquals(urlOfFileNode + " must be accessible after createNode",200,status);
+
+        /*
+        We should check the data, but nt:resources are not handled yet
+        // compare data with local file (just length)
+        final byte[] data = get.getResponseBody();
+        assertEquals("size of file must be same", localFile.length(), data.length);
+        */
+        String data = get.getResponseBodyAsString();
+        assertTrue("checking for content", data.contains("http://www.apache.org/licenses/LICENSE-2.0"));
+
+        // download structure
+        String json = getContent(urlOfFileNode + ".json", CONTENT_TYPE_JSON);
+        // just check for some strings
+        assertTrue("checking primary type", json.contains("\"jcr:primaryType\":\"nt:resource\""));
+        assertTrue("checking mime type", json.contains("\"jcr:mimeType\":\"text/plain\""));
+
+    }
+
+    public void testDistinctResourceWithType() throws IOException {
+        String folderPath = "/UploadFileTest_1_" + System.currentTimeMillis();
+        final String url = HTTP_BASE_URL + folderPath;
+
+        // create new node
+        String urlOfNewNode = null;
+        try {
+            urlOfNewNode = testClient.createNode(url, null);
+        } catch(IOException ioe) {
+            fail("createNode failed: " + ioe);
+        }
+
+        // upload local file
+        File localFile = new File(TEST_FILE);
+        testClient.uploadToFileNode(urlOfNewNode, localFile, "./file", "nt:unstructured");
+
+        // get and check URL of created file
+        String urlOfFileNode = urlOfNewNode + "/file";
+        final GetMethod get = new GetMethod(urlOfFileNode);
+        final int status = httpClient.executeMethod(get);
+        assertEquals(urlOfFileNode + " must be accessible after createNode",200,status);
+
+        /*
+        We should check the data, but nt:resources are not handled yet
+        // compare data with local file (just length)
+        final byte[] data = get.getResponseBody();
+        assertEquals("size of file must be same", localFile.length(), data.length);
+        */
+        String data = get.getResponseBodyAsString();
+        assertTrue("checking for content", data.contains("http://www.apache.org/licenses/LICENSE-2.0"));
+
+        // download structure
+        String json = getContent(urlOfFileNode + ".100.json", CONTENT_TYPE_JSON);
+
+        // just check for some strings
+        assertTrue("checking primary type", json.contains("\"jcr:primaryType\":\"nt:unstructured\""));
+        assertTrue("checking mime type", json.contains("\"jcr:mimeType\":\"text/plain\""));
+    }
+
+    public void testDistinctFile() throws IOException {
+        String folderPath = "/UploadFileTest_1_" + System.currentTimeMillis();
+        testClient.mkdirs(WEBDAV_BASE_URL, folderPath);
+        final String url = HTTP_BASE_URL + folderPath;
+
+
+        // upload local file
+        File localFile = new File(TEST_FILE);
+        testClient.uploadToFileNode(url, localFile, "./file", null);
+
+        // get and check URL of created file
+        String urlOfFileNode = url + "/file";
+
+        /*
+        TODO: does not work, since no nt:file resource type handler present ???
+
+        final GetMethod get = new GetMethod(urlOfFileNode);
+        final int status = httpClient.executeMethod(get);
+        assertEquals(urlOfFileNode + " must be accessible after createNode",200,status);
+
+        // compare data with local file (just length)
+        final byte[] data = get.getResponseBody();
+        assertEquals("size of file must be same", localFile.length(), data.length);
+        */
+
+        String webdavUrl = WEBDAV_BASE_URL + folderPath + "/file";
+        final GetMethod get = new GetMethod(webdavUrl);
+        final int status = httpClient.executeMethod(get);
+        assertEquals(urlOfFileNode + " must be accessible after createNode",200,status);
+
+        // compare data with local file (just length)
+        final byte[] data = get.getResponseBody();
+        assertEquals("size of file must be same", localFile.length(), data.length);
+
+        // download structure
+        String json = getContent(urlOfFileNode + ".json", CONTENT_TYPE_JSON);
+        // just check for some strings
+        assertTrue("checking primary type", json.contains("\"jcr:primaryType\":\"nt:file\""));
+    }
+
+    
+    public void testMultiFileUpload() throws IOException {
+        String folderPath = "/UploadFileTest_1_" + System.currentTimeMillis();
+        final String url = HTTP_BASE_URL + folderPath;
+
+        // create new node
+        String urlOfNewNode = null;
+        try {
+            urlOfNewNode = testClient.createNode(url, null);
+        } catch(IOException ioe) {
+            fail("createNode failed: " + ioe);
+        }
+
+        // upload local file
+        File [] localFiles = new File[] {
+        	new File(TEST_FILE),
+        	new File(TEST_FILE),
+        	new File(TEST_FILE)
+        };
+        String [] fieldNames = new String [] {
+        		"./file1.txt",
+        		"./file2.txt",
+        		"./*"        		
+        };
+        testClient.uploadToFileNodes(urlOfNewNode, localFiles, fieldNames, null);
+
+        // get and check URL of created file1
+        String urlOfFileNode = urlOfNewNode + "/file1.txt";
+        checkUploadedFileState(urlOfFileNode);    	
+
+        // get and check URL of created file2
+        String urlOfFileNode2 = urlOfNewNode + "/file2.txt";
+        checkUploadedFileState(urlOfFileNode2);    	
+
+        // get and check URL of created file3
+        String urlOfFileNode3 = urlOfNewNode + "/file-to-upload.txt";
+        checkUploadedFileState(urlOfFileNode3);    	
+    }
+
+	private void checkUploadedFileState(String urlOfFileNode) throws IOException,
+			HttpException {
+		final GetMethod get = new GetMethod(urlOfFileNode);
+        final int status = httpClient.executeMethod(get);
+        assertEquals(urlOfFileNode + " must be accessible after createNode",200,status);
+
+        /*
+        We should check the data, but nt:resources are not handled yet
+        // compare data with local file (just length)
+        final byte[] data = get.getResponseBody();
+        assertEquals("size of file must be same", localFile.length(), data.length);
+        */
+        String data = get.getResponseBodyAsString();
+        assertTrue("checking for content", data.contains("http://www.apache.org/licenses/LICENSE-2.0"));
+
+        // download structure
+        String json = getContent(urlOfFileNode + ".json", CONTENT_TYPE_JSON);
+        // just check for some strings
+        assertTrue("checking primary type", json.contains("\"jcr:primaryType\":\"nt:file\""));
+
+        String content_json = getContent(urlOfFileNode + "/jcr:content.json", CONTENT_TYPE_JSON);
+        // just check for some strings
+        assertTrue("checking primary type", content_json.contains("\"jcr:primaryType\":\"nt:resource\""));
+        assertTrue("checking mime type", content_json.contains("\"jcr:mimeType\":\"text/plain\""));
+	}
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/ValueFromTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/ValueFromTest.java
new file mode 100644
index 0000000..3e68c6c
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/ValueFromTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test the @ValueFrom field name suffix, SLING-130 */
+public class ValueFromTest extends HttpTestBase {
+
+    private String postUrl;
+    private String testText;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        
+        // set test values
+        testText = "This is a test " + System.currentTimeMillis();
+        
+        // create the test node, under a path that's specific to this class to allow collisions
+        postUrl = HTTP_BASE_URL + "/" + getClass().getSimpleName() + "/" + System.currentTimeMillis() + SlingPostConstants.DEFAULT_CREATE_SUFFIX;
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("text", testText);
+    }
+    
+    public void testWithoutValueFrom() throws IOException {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("./text", testText);
+        final String jsonUrl = testClient.createNode(postUrl, props) + ".json";
+        final String json = getContent(jsonUrl, CONTENT_TYPE_JSON);
+        assertJavascript(testText, json, "out.println(data.text)"); 
+        
+    }
+    
+    public void testWithValueFrom() throws IOException {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("./text@ValueFrom", "fulltext");
+        props.put("fulltext", testText);
+        final String jsonUrl = testClient.createNode(postUrl, props) + ".json";
+        final String json = getContent(jsonUrl, CONTENT_TYPE_JSON);
+        assertJavascript("string", json, "out.println(typeof data.text)"); 
+        assertJavascript(testText, json, "out.println(data.text)"); 
+        assertJavascript("undefined", json, "out.println(typeof data.fulltext)"); 
+    }
+    
+    public void testWithValueFromAndMissingField() throws IOException {
+        final Map<String,String> props = new HashMap<String,String>();
+        props.put("./jcr:created", "");
+        props.put("./text@ValueFrom", "fulltext");
+
+        // no fulltext field on purpose, field must be ignored
+        
+        final String jsonUrl = testClient.createNode(postUrl, props) + ".json";
+        final String json = getContent(jsonUrl, CONTENT_TYPE_JSON);
+        assertJavascript("undefined", json, "out.println(typeof data.text)"); 
+        assertJavascript("undefined", json, "out.println(typeof data['text@ValueFrom'])"); 
+    }
+    
+    
+    
+ }
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/WebdavUploadTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/WebdavUploadTest.java
new file mode 100644
index 0000000..4017874
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/WebdavUploadTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.launchpad.webapp.integrationtest;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/** Test WebDAV upload of various file types */
+public class WebdavUploadTest extends HttpTestBase {
+    
+    private final String testDir = "/sling-test/" + getClass().getSimpleName() + System.currentTimeMillis();
+    private final String testDirUrl = WEBDAV_BASE_URL + testDir;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        testClient.mkdirs(WEBDAV_BASE_URL, testDir);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        testClient.delete(testDirUrl);
+    }
+
+    protected byte [] readStream(InputStream is) throws IOException {
+        if(is == null) {
+            fail("Null InputStream");
+        }
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        try {
+            final byte [] buffer = new byte[4096];
+            int n = 0;
+            while( (n = is.read(buffer, 0, buffer.length)) > 0) {
+                bos.write(buffer, 0, n);
+            }
+        } finally {
+            is.close();
+            bos.flush();
+            bos.close();
+        }
+        return bos.toByteArray();
+    }
+    
+    protected void compareData(String slingDataUrl, String localResourcePath) throws IOException {
+        
+        // Get Sling content as a binary stream
+        final GetMethod m = new GetMethod(slingDataUrl);
+        final int httpStatus = httpClient.executeMethod(m);
+        assertEquals("GET " + slingDataUrl + " must return status 200", 200, httpStatus);
+        final byte [] local = readStream(getClass().getResourceAsStream(localResourcePath));
+        final byte [] remote = readStream(m.getResponseBodyAsStream());
+        
+        assertEquals("Local and remote files have the same length", local.length, remote.length);
+        
+        for(int i=0 ; i < local.length; i++) {
+            assertEquals("Content must match at index " + i, local[i], remote[i]);
+        }
+    }
+    
+    protected void uploadAndCheck(String localResourcePath) throws IOException {
+        final InputStream data = getClass().getResourceAsStream(localResourcePath);
+        if(data==null) {
+            fail("Local resource not found: " + localResourcePath);
+        }
+        
+        try {
+            final String url = testDirUrl + "/" + new File(localResourcePath).getName();
+            testClient.upload(url, data); 
+            compareData(url, localResourcePath);
+        } finally {
+            if(data!=null) {
+                data.close();
+            }
+        }
+        
+    }
+    
+    public void testTextUpload() throws IOException {
+        uploadAndCheck("/integration-test/testfile.txt");
+    }
+    
+    public void testXmlUpload() throws IOException {
+        uploadAndCheck("/integration-test/testfile.xml");
+    }
+    
+    public void testZipUpload() throws IOException {
+        uploadAndCheck("/integration-test/testfile.zip");
+    }
+    
+    public void testPngUpload() throws IOException {
+        uploadAndCheck("/integration-test/sling-logo.png");
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/AbstractAccessManagerTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/AbstractAccessManagerTest.java
new file mode 100644
index 0000000..2ce7106
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/AbstractAccessManagerTest.java
@@ -0,0 +1,196 @@
+/*
+ * 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.launchpad.webapp.integrationtest.accessManager;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthScope;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/**
+ * Base class for AccessManager tests.
+ */
+public abstract class AbstractAccessManagerTest extends HttpTestBase {
+
+	public static final String TEST_BASE_PATH = "/sling-tests";
+
+    /** Execute a POST request and check status */
+    protected void assertAuthenticatedPostStatus(Credentials creds, String url, int expectedStatusCode, List<NameValuePair> postParams, String assertMessage)
+    throws IOException {
+        final PostMethod post = new PostMethod(url);
+        post.setFollowRedirects(false);
+        
+        URL baseUrl = new URL(HTTP_BASE_URL);
+        AuthScope authScope = new AuthScope(baseUrl.getHost(), baseUrl.getPort(), AuthScope.ANY_REALM);
+        post.setDoAuthentication(true);
+        Credentials oldCredentials = httpClient.getState().getCredentials(authScope);
+        try {
+			httpClient.getState().setCredentials(authScope, creds);
+	        
+	        if(postParams!=null) {
+	            final NameValuePair [] nvp = {};
+	            post.setRequestBody(postParams.toArray(nvp));
+	        }
+	
+	        final int status = httpClient.executeMethod(post);
+	        if(assertMessage == null) {
+	            assertEquals(expectedStatusCode, status);
+	        } else {
+	            assertEquals(assertMessage, expectedStatusCode, status);
+	        }
+        } finally {
+        	httpClient.getState().setCredentials(authScope, oldCredentials);
+        }
+    }
+
+    /** Verify that given URL returns expectedStatusCode
+     * @throws IOException */
+    protected void assertAuthenticatedHttpStatus(Credentials creds, String urlString, int expectedStatusCode, String assertMessage) throws IOException {
+        URL baseUrl = new URL(HTTP_BASE_URL);
+        AuthScope authScope = new AuthScope(baseUrl.getHost(), baseUrl.getPort(), AuthScope.ANY_REALM);
+        GetMethod getMethod = new GetMethod(urlString);
+        getMethod.setDoAuthentication(true);
+        
+        Credentials oldCredentials = httpClient.getState().getCredentials(authScope);
+    	try {
+			httpClient.getState().setCredentials(authScope, creds);
+
+			final int status = httpClient.executeMethod(getMethod);
+            if(assertMessage == null) {
+                assertEquals(urlString,expectedStatusCode, status);
+            } else {
+                assertEquals(assertMessage, expectedStatusCode, status);
+            }
+    	} finally {
+        	httpClient.getState().setCredentials(authScope, oldCredentials);
+    	}
+    }
+
+    
+    /** retrieve the contents of given URL and assert its content type
+     * @param expectedContentType use CONTENT_TYPE_DONTCARE if must not be checked 
+     * @throws IOException
+     * @throws HttpException */
+    protected String getAuthenticatedContent(Credentials creds, String url, String expectedContentType, List<NameValuePair> params, int expectedStatusCode) throws IOException {
+        final GetMethod get = new GetMethod(url);
+
+        URL baseUrl = new URL(HTTP_BASE_URL);
+        AuthScope authScope = new AuthScope(baseUrl.getHost(), baseUrl.getPort(), AuthScope.ANY_REALM);
+        get.setDoAuthentication(true);
+        Credentials oldCredentials = httpClient.getState().getCredentials(authScope);
+    	try {
+			httpClient.getState().setCredentials(authScope, creds);
+			
+	        if(params != null) {
+	            final NameValuePair [] nvp = new NameValuePair[0];
+	            get.setQueryString(params.toArray(nvp));
+	        }
+	        final int status = httpClient.executeMethod(get);
+	        final InputStream is = get.getResponseBodyAsStream();
+	        final StringBuffer content = new StringBuffer();
+	        final String charset = get.getResponseCharSet();
+	        final byte [] buffer = new byte[16384];
+	        int n = 0;
+	        while( (n = is.read(buffer, 0, buffer.length)) > 0) {
+	            content.append(new String(buffer, 0, n, charset));
+	        }
+	        assertEquals("Expected status " + expectedStatusCode + " for " + url + " (content=" + content + ")",
+	                expectedStatusCode,status);
+	        final Header h = get.getResponseHeader("Content-Type");
+	        if(expectedContentType == null) {
+	            if(h!=null) {
+	                fail("Expected null Content-Type, got " + h.getValue());
+	            }
+	        } else if(CONTENT_TYPE_DONTCARE.equals(expectedContentType)) {
+	            // no check
+	        } else if(h==null) {
+	            fail(
+	                    "Expected Content-Type that starts with '" + expectedContentType
+	                    +" but got no Content-Type header at " + url
+	            );
+	        } else {
+	            assertTrue(
+	                "Expected Content-Type that starts with '" + expectedContentType
+	                + "' for " + url + ", got '" + h.getValue() + "'",
+	                h.getValue().startsWith(expectedContentType)
+	            );
+	        }
+	        return content.toString();
+			
+    	} finally {
+        	httpClient.getState().setCredentials(authScope, oldCredentials);
+    	}
+    }
+    
+    
+    protected static int counter = 1;
+    
+	protected String createTestUser() throws IOException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user.create.html";
+
+		String testUserId = "testUser" + (counter++);
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":name", testUserId));
+		postParams.add(new NameValuePair("pwd", "testPwd"));
+		postParams.add(new NameValuePair("pwdConfirm", "testPwd"));
+		assertPostStatus(postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		return testUserId;
+	}
+    
+	protected String createTestGroup() throws IOException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/group.create.html";
+
+		String testGroupId = "testGroup" + (counter++);
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":name", testGroupId));
+		
+		//success would be a redirect to the welcome page of the webapp
+        Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		return testGroupId;
+	}
+	
+	protected String createTestFolder() throws IOException {
+        String postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + "testFolder" + (counter++);
+
+        final String location = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
+        assertHttpStatus(location + DEFAULT_EXT, HttpServletResponse.SC_OK,
+                "POST must redirect to created resource (" + location + ")");
+        assertTrue("Node (" + location + ") must have generated name",
+                !location.endsWith("/*"));
+        assertTrue("Node (" + location + ") must created be under POST URL (" + postUrl + ")",
+                location.contains(postUrl + "/"));
+
+        return location;
+	}
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/ModifyAceTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/ModifyAceTest.java
new file mode 100644
index 0000000..87dd33c
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/ModifyAceTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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.launchpad.webapp.integrationtest.accessManager;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.sling.commons.json.JSONArray;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+
+/**
+ * Tests for the 'modifyAce' Sling Post Operation
+ */
+public class ModifyAceTest extends AbstractAccessManagerTest {
+
+	String testUserId = null;
+	String testGroupId = null;
+	String testFolderUrl = null;
+	
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
+
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+
+		if (testFolderUrl != null) {
+			//remove the test user if it exists.
+			String postUrl = testFolderUrl;
+			List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+			postParams.add(new NameValuePair(":operation", "delete"));
+			assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		}
+		if (testGroupId != null) {
+			//remove the test user if it exists.
+			String postUrl = HTTP_BASE_URL + "/system/userManager/group/" + testGroupId + ".delete.html";
+			List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+			assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		}
+		if (testUserId != null) {
+			//remove the test user if it exists.
+			String postUrl = HTTP_BASE_URL + "/system/userManager/user/" + testUserId + ".delete.html";
+			List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+			assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		}
+	}
+
+	public void testModifyAceForUser() throws IOException, JSONException {
+		testUserId = createTestUser();
+		
+		testFolderUrl = createTestFolder();
+		
+        String postUrl = testFolderUrl + ".modifyAce.html";
+
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair("principalId", testUserId));
+		postParams.add(new NameValuePair("privilege@jcr:read", "granted"));
+		postParams.add(new NameValuePair("privilege@jcr:write", "denied"));
+		
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		
+		//fetch the JSON for the acl to verify the settings.
+		String getUrl = testFolderUrl + ".acl.json";
+
+		String json = getAuthenticatedContent(creds, getUrl, CONTENT_TYPE_JSON, null, HttpServletResponse.SC_OK);
+		assertNotNull(json);
+		JSONObject jsonObj = new JSONObject(json);
+		String aceString = jsonObj.getString(testUserId);
+		assertNotNull(aceString);
+		
+		JSONObject aceObject = new JSONObject(aceString); 
+		assertNotNull(aceObject);
+		
+		JSONArray grantedArray = aceObject.getJSONArray("granted");
+		assertNotNull(grantedArray);
+		assertEquals("jcr:read", grantedArray.getString(0));
+
+		JSONArray deniedArray = aceObject.getJSONArray("denied");
+		assertNotNull(deniedArray);
+		assertEquals("jcr:write", deniedArray.getString(0));
+	}
+
+	public void testModifyAceForGroup() throws IOException, JSONException {
+		testGroupId = createTestGroup();
+
+		testFolderUrl = createTestFolder();
+
+        String postUrl = testFolderUrl + ".modifyAce.html";
+
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair("principalId", testGroupId));
+		postParams.add(new NameValuePair("privilege@jcr:read", "granted"));
+		postParams.add(new NameValuePair("privilege@jcr:write", "denied"));
+		
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		
+		//fetch the JSON for the acl to verify the settings.
+		String getUrl = testFolderUrl + ".acl.json";
+
+		String json = getAuthenticatedContent(creds, getUrl, CONTENT_TYPE_JSON, null, HttpServletResponse.SC_OK);
+		assertNotNull(json);
+		JSONObject jsonObj = new JSONObject(json);
+		String aceString = jsonObj.getString(testGroupId);
+		assertNotNull(aceString);
+
+		JSONObject aceObject = new JSONObject(aceString);
+		assertNotNull(aceObject);
+		
+		JSONArray grantedArray = aceObject.getJSONArray("granted");
+		assertNotNull(grantedArray);
+		assertEquals("jcr:read", grantedArray.getString(0));
+
+		//denied rights are not applied for groups, so make sure it is not there
+		assertTrue(aceObject.isNull("denied"));
+	}
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/RemoveAcesTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/RemoveAcesTest.java
new file mode 100644
index 0000000..5049c44
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/RemoveAcesTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.launchpad.webapp.integrationtest.accessManager;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.sling.commons.json.JSONArray;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+
+/**
+ * Tests for the 'removeAce' Sling POST operation
+ */
+public class RemoveAcesTest extends AbstractAccessManagerTest {
+	String testUserId = null;
+	String testGroupId = null;
+	String testFolderUrl = null;
+	
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
+
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+
+		if (testFolderUrl != null) {
+			//remove the test user if it exists.
+			String postUrl = testFolderUrl;
+			List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+			postParams.add(new NameValuePair(":operation", "delete"));
+			assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		}
+		if (testGroupId != null) {
+			//remove the test user if it exists.
+			String postUrl = HTTP_BASE_URL + "/system/userManager/group/" + testGroupId + ".delete.html";
+			List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+			assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		}
+		if (testUserId != null) {
+			//remove the test user if it exists.
+			String postUrl = HTTP_BASE_URL + "/system/userManager/user/" + testUserId + ".delete.html";
+			List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+			assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		}
+		//todo delete test folder
+	}
+	
+	private String createFolderWithAces(boolean addGroupAce) throws IOException, JSONException {
+		testUserId = createTestUser();
+		testFolderUrl = createTestFolder();
+
+        String postUrl = testFolderUrl + ".modifyAce.html";
+
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair("principalId", testUserId));
+		postParams.add(new NameValuePair("privilege@jcr:read", "granted"));
+		postParams.add(new NameValuePair("privilege@jcr:write", "denied"));
+		
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+
+		if (addGroupAce) {
+			testGroupId = createTestGroup();
+			
+			postParams = new ArrayList<NameValuePair>();
+			postParams.add(new NameValuePair("principalId", testGroupId));
+			postParams.add(new NameValuePair("privilege@jcr:read", "granted"));
+			
+			assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		}
+		
+		//fetch the JSON for the acl to verify the settings.
+		String getUrl = testFolderUrl + ".acl.json";
+
+		String json = getAuthenticatedContent(creds, getUrl, CONTENT_TYPE_JSON, null, HttpServletResponse.SC_OK);
+		assertNotNull(json);
+		
+		JSONObject jsonObj = new JSONObject(json);
+		String aceString = jsonObj.getString(testUserId);
+		assertNotNull(aceString);
+
+		JSONObject aceObject = new JSONObject(aceString);
+		assertNotNull(aceObject);
+		
+		JSONArray grantedArray = aceObject.getJSONArray("granted");
+		assertNotNull(grantedArray);
+		assertEquals("jcr:read", grantedArray.getString(0));
+
+		JSONArray deniedArray = aceObject.getJSONArray("denied");
+		assertNotNull(deniedArray);
+		assertEquals("jcr:write", deniedArray.getString(0));
+
+		if (addGroupAce) {
+			aceString = jsonObj.getString(testGroupId);
+			assertNotNull(aceString);
+
+			aceObject = new JSONObject(aceString);
+			assertNotNull(aceObject);
+
+			grantedArray = aceObject.getJSONArray("granted");
+			assertNotNull(grantedArray);
+			assertEquals("jcr:read", grantedArray.getString(0));
+		}
+		
+		return testFolderUrl;
+	}
+	
+	//test removing a single ace
+	public void testRemoveAce() throws IOException, JSONException {
+		String folderUrl = createFolderWithAces(false);
+		
+		//remove the ace for the testUser principal
+		String postUrl = folderUrl + ".deleteAce.html"; 
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":applyTo", testUserId));
+        Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+
+		//fetch the JSON for the acl to verify the settings.
+		String getUrl = folderUrl + ".acl.json";
+
+		String json = getAuthenticatedContent(creds, getUrl, CONTENT_TYPE_JSON, null, HttpServletResponse.SC_OK);
+		assertNotNull(json);
+
+		JSONObject jsonObj = new JSONObject(json);
+		assertTrue(jsonObj.isNull(testUserId));
+	}
+
+	//test removing multiple aces
+	public void testRemoveAces() throws IOException, JSONException {
+		String folderUrl = createFolderWithAces(true);
+		
+		//remove the ace for the testUser principal
+		String postUrl = folderUrl + ".deleteAce.html"; 
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":applyTo", testUserId));
+		postParams.add(new NameValuePair(":applyTo", testGroupId));
+        Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+
+		//fetch the JSON for the acl to verify the settings.
+		String getUrl = folderUrl + ".acl.json";
+
+		String json = getAuthenticatedContent(creds, getUrl, CONTENT_TYPE_JSON, null, HttpServletResponse.SC_OK);
+		assertNotNull(json);
+
+		JSONObject jsonObj = new JSONObject(json);
+		assertTrue(jsonObj.isNull(testUserId));
+		assertTrue(jsonObj.isNull(testGroupId));
+	}
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/issues/SLING457Test.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/issues/SLING457Test.java
new file mode 100644
index 0000000..5c352c2
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/issues/SLING457Test.java
@@ -0,0 +1,89 @@
+/*
+ * 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.launchpad.webapp.integrationtest.issues;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+public class SLING457Test extends HttpTestBase {
+
+    private String testRootUrl;
+
+    private String contentUrl;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final String testRootPathBare = "/" + getClass().getSimpleName() + "/"
+            + System.currentTimeMillis();
+        final String testRootPath = HTTP_BASE_URL + testRootPathBare;
+
+        // the root for our tests
+        testRootUrl = testClient.createNode(testRootPath, null);
+
+        // create the Resource Type "a" location
+        String rtA = testRootPathBare + "/a";
+        testClient.createNode(HTTP_BASE_URL + rtA, null);
+
+        // create the Resource Type "b" location
+        String rtB = testRootPathBare + "/b";
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("sling:resourceSuperType", rtA);
+        testClient.createNode(HTTP_BASE_URL + rtB, props);
+
+        // create content node "x" of type rtB
+        String rtX = testRootPathBare + "/x";
+        props.clear();
+        props.put("sling:resourceType", rtB);
+        contentUrl = testClient.createNode(HTTP_BASE_URL + rtX, props);
+
+        // create content node "x/image" of type rtB
+        String rtXImage = rtX + "/image";
+        props.clear();
+        props.put("sling:resourceType", "nt:unstructured");
+        testClient.createNode(HTTP_BASE_URL + rtXImage, props);
+
+        uploadTestScript(rtA, "issues/sling457/a-foo.html.jsp", "foo.html.jsp");
+        uploadTestScript(rtB, "issues/sling457/b-b.jsp", "b.jsp");
+
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        testClient.delete(testRootUrl);
+        super.tearDown();
+    }
+
+    public void testCallFooHtml() throws Exception {
+        String url = contentUrl + ".foo.html";
+        String content = getContent(url, CONTENT_TYPE_HTML);
+        assertTrue("Expected 'foo.html.jsp' in content",
+            content.indexOf("foo.html.jsp") >= 0);
+    }
+
+    public void testCallHtml() throws Exception {
+        String url = contentUrl + ".html";
+        String content = getContent(url, CONTENT_TYPE_HTML);
+        assertTrue("Expected 'foo.html.jsp' in content",
+            content.indexOf("foo.html.jsp") >= 0);
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/issues/SLING760Test.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/issues/SLING760Test.java
new file mode 100644
index 0000000..e558fc4
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/issues/SLING760Test.java
@@ -0,0 +1,56 @@
+/*
+ * 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.launchpad.webapp.integrationtest.issues;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+public class SLING760Test extends HttpTestBase {
+    public static final String TEST_PATH = "/" + SLING760Test.class.getSimpleName();
+
+    /** Verify that all instances of our error message are escaped in response, which
+     *  is generated by the default Sling error handler */
+    public void testEscapedErrorMessages() throws Exception {
+        final String [] mustContain = { "&lt;characters/&gt;", "filtered &amp; escaped" };
+        final String [] mustNotContain = { "<characters/>", "filtered & escaped" };
+
+        final TestNode tn = new TestNode(HTTP_BASE_URL + TEST_PATH, null);
+
+        String toDelete = null;
+        try {
+            toDelete = uploadTestScript(tn.scriptPath, "issues/sling760/throw-with-markup.esp", "html.esp");
+            final String content = getContent(tn.nodeUrl + ".html", CONTENT_TYPE_HTML,
+                    null, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+
+            for(String str : mustContain) {
+                assertTrue("Content must contain " + str + " (" + content + ")", content.contains(str));
+            }
+
+            for(String str : mustNotContain) {
+                assertFalse("Content must NOT contain " + str + " (" + content + ")", content.contains(str));
+            }
+        } finally {
+            if (toDelete != null) {
+                testClient.delete(toDelete);
+            }
+            tn.delete();
+        }
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/package.html b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/package.html
new file mode 100644
index 0000000..b4c0c84
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/package.html
@@ -0,0 +1,20 @@
+<html>
+<body>
+  <p>
+    The tests found in and under this package are used in the 
+    "integration-test" build phase (SLING-82), they are not run 
+    as part of the normal "test" build phase. 
+  </p>
+  <p>
+    To debug the integration tests, however, it is useful to run
+    them as part of the normal test phase, after starting a separate
+    Sling instance that they can talk to.
+  </p>
+  <p>
+    This is implemented using Maven profiles: to run the integration
+    tests during the normal test phase, disable the "disableIntegrationTestsInTestPhase"
+    Maven profile, for example using <code>mvn -P nullUslingProfile test</code>.
+    See pom.xml for more details.
+  </p>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtCopyTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtCopyTest.java
new file mode 100644
index 0000000..d1bfcfc
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtCopyTest.java
@@ -0,0 +1,199 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/** Test item copy support by @CopyFrom suffix (SLING-455) */
+public class PostServletAtCopyTest extends HttpTestBase {
+
+    public static final String TEST_BASE_PATH = "/sling-at-copy-tests";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public void testCopyNodeAbsolute() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/abs/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // assert content at source location
+        final String oldContent = getContent(HTTP_BASE_URL + testPath + "/src.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+        // create dest with text set from src/text
+        props.clear();
+        props.put("src@CopyFrom", testPath + "/src");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.src.text)");
+
+        // assert content at old location
+        String contentOld = getContent(HTTP_BASE_URL + testPath + "/src.-1.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", contentOld, "out.println(data.text)");
+    }
+
+    public void testCopyNodeRelative() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/rel/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // assert content at source location
+        final String oldContent = getContent(HTTP_BASE_URL + testPath + "/src.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+        // create dest with text set from src/text
+        props.clear();
+        props.put("src@CopyFrom", "../src");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.src.text)");
+
+        // assert content at old location
+        String contentOld = getContent(HTTP_BASE_URL + testPath + "/src.-1.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", contentOld, "out.println(data.text)");
+    }
+
+    public void testCopyPropertyAbsolute() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/abs/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // assert content at source location
+        final String oldContent = getContent(HTTP_BASE_URL + testPath + "/src.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+        // create dest with text set from src/text
+        props.clear();
+        props.put("text@CopyFrom", testPath + "/src/text");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+
+        // assert content at old location
+        String contentOld = getContent(HTTP_BASE_URL + testPath + "/src.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", contentOld, "out.println(data.text)");
+    }
+
+    public void testCopyPropertyRelative() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/rel/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // assert content at source location
+        final String oldContent = getContent(HTTP_BASE_URL + testPath + "/src.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+        // create dest with text set from src/text
+        props.clear();
+        props.put("text@CopyFrom", "../src/text");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+
+        // assert content at old location
+        String contentOld = getContent(HTTP_BASE_URL + testPath + "/src.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", contentOld, "out.println(data.text)");
+    }
+
+    public void testCopyNodeSourceMissing() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/exist/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+
+        // create dest node
+        props.clear();
+        props.put("text", "Hello Destination");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest/src", props);
+
+        props.clear();
+        props.put("src@CopyFrom", testPath + "/non_existing_source");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // expect unmodified dest
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello Destination", content, "out.println(data.src.text)");
+    }
+
+    public void testCopyNodeExistingReplace() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/replace/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // create dest node
+        props.clear();
+        props.put("text", "Hello Destination");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest/src", props);
+
+        props.clear();
+        props.put("src@CopyFrom", "../src");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // expect unmodified dest
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.src.text)");
+    }
+
+    public void testCopyNodeDeepRelative() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/new/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        props.clear();
+        props.put("deep/new@CopyFrom", "../../src");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // expect new data
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.deep['new'].text)");
+    }
+
+    public void testCopyNodeDeepAbsolute() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/new_fail/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        props.clear();
+        props.put(testPath + "/some/not/existing/structure@CopyFrom", testPath + "/src");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/*", props);
+
+        // expect new data
+        String content = getContent(HTTP_BASE_URL + testPath + "/some/not/existing/structure.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+    }
+
+ }
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtDeleteTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtDeleteTest.java
new file mode 100644
index 0000000..f497602
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtDeleteTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test support of @Delete suffix of SLING-458 */
+public class PostServletAtDeleteTest extends HttpTestBase {
+    public static final String TEST_BASE_PATH = "/sling-tests";
+    
+    private static final String PROP_NAME = "text";
+    private static final String PROP_NAME2 = "title";
+    
+    private static final String PROP_VALUE = "some value";
+    private static final String PROP_VALUE2 = "title value";
+    
+    private String postUrl;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + getClass().getSimpleName() + "/" + System.currentTimeMillis();
+
+        assertHttpStatus(postUrl, HttpServletResponse.SC_NOT_FOUND,
+                "Path must not exist before test: " + postUrl);
+    }
+
+    public void testDeleteOnly() throws Exception {
+        final Map<String, String> props = new HashMap<String, String>();
+        props.put(PROP_NAME, PROP_VALUE);
+        final String contentURL = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        
+        try {
+            // assert property is set correctly
+            final String propURL = contentURL + "/" + PROP_NAME;
+            final String data = getContent(propURL + ".json", CONTENT_TYPE_JSON);
+            final JSONObject json = new JSONObject(data);
+            assertEquals(PROP_VALUE, json.get(PROP_NAME));
+            
+            final List <NameValuePair> params = new LinkedList<NameValuePair> ();
+            params.add(new NameValuePair(PROP_NAME + SlingPostConstants.SUFFIX_DELETE, "don't care"));
+            
+            assertPostStatus(contentURL, HttpServletResponse.SC_OK, params, PROP_NAME + " must be deleted");
+            assertHttpStatus(propURL, HttpServletResponse.SC_NOT_FOUND, PROP_NAME + " must be deleted");
+        } finally {
+            deleteNode(contentURL);
+        }
+    }
+    
+    public void testDeleteWithModify() throws Exception {
+        final Map<String, String> props = new HashMap<String, String>();
+        props.put(PROP_NAME, PROP_VALUE);
+        final String contentURL = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+
+        try {
+            // assert property is set correctly
+            final String propURL = contentURL + "/" + PROP_NAME;
+            final String data = getContent(propURL + ".json", CONTENT_TYPE_JSON);
+            final JSONObject json = new JSONObject(data);
+            assertEquals(PROP_VALUE, json.get(PROP_NAME));
+            
+            final List <NameValuePair> params = new LinkedList<NameValuePair> ();
+            params.add(new NameValuePair(PROP_NAME + SlingPostConstants.SUFFIX_DELETE, "don't care"));
+            params.add(new NameValuePair(PROP_NAME2, PROP_VALUE2));
+    
+            assertPostStatus(contentURL, HttpServletResponse.SC_OK, params, PROP_NAME + " must be deleted");
+            assertHttpStatus(propURL, HttpServletResponse.SC_NOT_FOUND, PROP_NAME + " must be deleted");
+            assertHttpStatus(contentURL + "/" + PROP_NAME2, HttpServletResponse.SC_OK, PROP_NAME2 + " must exist");
+
+            final String data2 = getContent(contentURL + ".json", CONTENT_TYPE_JSON);
+            final JSONObject json2 = new JSONObject(data2);
+            assertFalse(json2.has(PROP_VALUE));
+            assertEquals(PROP_VALUE2, json2.get(PROP_NAME2));
+
+        } finally {
+            deleteNode(contentURL);
+        }
+    }
+    
+    protected void deleteNode(String nodeURL) throws IOException {
+        // delete one and check
+        final List <NameValuePair> params = new LinkedList<NameValuePair> ();
+        params.add(new NameValuePair(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_DELETE));
+        assertPostStatus(nodeURL, HttpServletResponse.SC_OK, params, nodeURL + " must be deleted");
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtMoveTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtMoveTest.java
new file mode 100644
index 0000000..61e53d2
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletAtMoveTest.java
@@ -0,0 +1,209 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/** Test item move support by @MoveFrom suffix (SLING-455) */
+public class PostServletAtMoveTest extends HttpTestBase {
+
+    public static final String TEST_BASE_PATH = "/sling-at-move-tests";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public void testMoveNodeAbsolute() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/abs/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // assert content at source location
+        final String oldContent = getContent(HTTP_BASE_URL + testPath + "/src.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+        // create dest with text set from src/text
+        props.clear();
+        props.put("src@MoveFrom", testPath + "/src");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.src.text)");
+
+        // assert no content at old location
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src.json",
+            HttpServletResponse.SC_NOT_FOUND,
+        "Expected Not_Found for old content");
+    }
+
+    public void testMoveNodeRelative() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/rel/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // assert content at source location
+        final String oldContent = getContent(HTTP_BASE_URL + testPath + "/src.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+        // create dest with text set from src/text
+        props.clear();
+        props.put("src@MoveFrom", "../src");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.src.text)");
+
+        // assert no content at old location
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src.json",
+            HttpServletResponse.SC_NOT_FOUND,
+        "Expected Not_Found for old content");
+    }
+
+    public void testMovePropertyAbsolute() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/abs/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // assert content at source location
+        final String oldContent = getContent(HTTP_BASE_URL + testPath + "/src.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+        // create dest with text set from src/text
+        props.clear();
+        props.put("text@MoveFrom", testPath + "/src/text");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+
+        // assert no content at old location
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src.json",
+            HttpServletResponse.SC_OK, "Expected source parent existing");
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src/text.json",
+            HttpServletResponse.SC_NOT_FOUND,
+            "Expected Not_Found for old content");
+    }
+
+    public void testMovePropertyRelative() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/rel/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // assert content at source location
+        final String oldContent = getContent(HTTP_BASE_URL + testPath + "/src.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", oldContent, "out.println(data.text)");
+
+        // create dest with text set from src/text
+        props.clear();
+        props.put("text@MoveFrom", "../src/text");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+
+        // assert no content at old location
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src.json",
+            HttpServletResponse.SC_OK, "Expected source parent existing");
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src/text.json",
+            HttpServletResponse.SC_NOT_FOUND,
+            "Expected Not_Found for old content");
+    }
+
+    public void testMoveNodeSourceMissing() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/exist/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+
+        // create dest node
+        props.clear();
+        props.put("text", "Hello Destination");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest/src", props);
+
+        props.clear();
+        props.put("src@MoveFrom", testPath + "/non_existing_source");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // expect unmodified dest
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello Destination", content, "out.println(data.src.text)");
+    }
+
+    public void testMoveNodeExistingReplace() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/replace/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // create dest node
+        props.clear();
+        props.put("text", "Hello Destination");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest/src", props);
+
+        props.clear();
+        props.put("src@MoveFrom", "../src");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // expect unmodified dest
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.src.text)");
+    }
+
+    public void testMoveNodeDeepRelative() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/new/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        props.clear();
+        props.put("deep/new@MoveFrom", "../../src");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // expect new data
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.deep['new'].text)");
+    }
+
+    public void testMoveNodeDeepAbsolute() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/new_fail/" + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        props.clear();
+        props.put(testPath + "/some/not/existing/structure@MoveFrom", testPath + "/src");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/*", props);
+
+        // expect new data
+        String content = getContent(HTTP_BASE_URL + testPath + "/some/not/existing/structure.json", CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+    }
+
+ }
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletCopyTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletCopyTest.java
new file mode 100644
index 0000000..c4cff8a
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletCopyTest.java
@@ -0,0 +1,445 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.commons.testing.integration.HttpStatusCodeException;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test node copy via the MicrojaxPostServlet */
+public class PostServletCopyTest extends HttpTestBase {
+
+    public static final String TEST_BASE_PATH = "/sling-copy-tests";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public void testCopyNodeAbsolute() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/abs/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY);
+        props.put(SlingPostConstants.RP_DEST, testPath + "/dest");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+
+        // assert content at old location
+        content = getContent(HTTP_BASE_URL + testPath + "/src.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+    }
+
+    public void testCopyNodeAbsoluteBelowDest() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/abs/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // first test: failure because dest (parent) does not exist
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        assertPostStatus(HTTP_BASE_URL + testPath + "/src",
+            HttpServletResponse.SC_PRECONDITION_FAILED, nvPairs,
+            "Expecting Copy Failure (dest must exist)");
+
+        // create dest as parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", null);
+
+        // copy now succeeds to below dest
+        assertPostStatus(HTTP_BASE_URL + testPath + "/src",
+            HttpServletResponse.SC_CREATED, nvPairs, "Expecting Copy Success");
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.src.text)");
+
+        // assert content at old location
+        content = getContent(HTTP_BASE_URL + testPath + "/src.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+    }
+
+    public void testCopyNodeRelative() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/rel/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY);
+        props.put(SlingPostConstants.RP_DEST, "dest");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+    }
+
+    public void testCopyNodeExistingFail() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/exist/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // create dest node
+        props.put("text", "Hello Destination");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY);
+        props.put(SlingPostConstants.RP_DEST, testPath + "/dest");
+        try {
+            testClient.createNode(HTTP_BASE_URL + testPath, props);
+        } catch (HttpStatusCodeException hsce) {
+            // if we do not get the status code 302 message, fail
+            if (hsce.getActualStatus() == 302) {
+                throw hsce;
+            }
+        }
+
+        // expect unmodified dest
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello Destination", content, "out.println(data.text)");
+    }
+
+    public void testCopyNodeExistingReplace() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/replace/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // create dest node
+        props.put("text", "Hello Destination");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY);
+        props.put(SlingPostConstants.RP_DEST, testPath + "/dest");
+        props.put(SlingPostConstants.RP_REPLACE, "true");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+    }
+
+    public void testCopyNodeDeepRelative() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/new/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY);
+        props.put(SlingPostConstants.RP_DEST, "deep/new");
+
+        try {
+            testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+            fail("Moving node to non existing parent location should fail.");
+        } catch (HttpStatusCodeException hsce) {
+            // actually the status is not 200, but we get "browser" clear stati
+            if (hsce.getActualStatus() != 200) {
+                throw hsce;
+            }
+        }
+    }
+
+    public void testCopyNodeDeepAbsolute() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/new_fail/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY);
+        props.put(SlingPostConstants.RP_DEST, "/some/not/existing/structure");
+        try {
+            testClient.createNode(HTTP_BASE_URL + testPath + "/*", props);
+            // not quite correct. should check status response
+            fail("Moving node to non existing parent location should fail.");
+        } catch (HttpStatusCodeException hsce) {
+            // actually the status is not 200, but we get "browser" clear stati
+            if (hsce.getActualStatus() != 200) {
+                throw hsce;
+            }
+        }
+    }
+
+    public void testCopyNodeMultipleSourceValid() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/cpmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src2", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src3", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src4", props);
+
+        // copy the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src3"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src4"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Copy Failure: dest parent does not exist");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // now dest exists, so we expect success
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Copy Success");
+
+        // assert existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_OK);
+
+        testClient.delete(testRoot);
+    }
+
+    public void testCopyNodeMultipleSourceInValid() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/cpmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src2", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src3", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src4", props);
+
+        // copy the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src3"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src4"));
+        assertPostStatus(testRoot,
+            HttpServletResponse.SC_INTERNAL_SERVER_ERROR, nvPairs,
+            "Expecting Copy Failure (dest must have trailing slash)");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // retest after creating test
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Copy Failure (dest already exists)");
+
+        // assert non-existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        testClient.delete(testRoot);
+    }
+
+    public void testCopyNodeMultipleSourcePartial() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/cpmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src3", props);
+
+        // copy the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src3"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src4"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Copy Failure: dest parent does not exist");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // now dest exists, so we expect success
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Copy Success");
+
+        // assert partial existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        testClient.delete(testRoot);
+    }
+
+    public void testCopyNodeMultipleSourceReplace() throws Exception {
+        final String testPath = TEST_BASE_PATH + "/cpmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src2", props);
+
+        // copy the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Copy Failure: dest parent does not exist");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", null);
+
+        // now dest exists, so we expect success
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Copy Success");
+
+        // assert partial existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        // assert content test
+        String content = getContent(HTTP_BASE_URL + testPath
+            + "/dest/src1.json", CONTENT_TYPE_JSON);
+        JSONObject json = new JSONObject(content);
+        assertEquals("Hello", json.get("text"));
+
+        // modify src1 content
+        nvPairs.clear();
+        nvPairs.add(new NameValuePair("text", "Modified Hello"));
+        assertPostStatus(HTTP_BASE_URL + testPath + "/src1",
+            HttpServletResponse.SC_OK, nvPairs, "Expect Content Update Success");
+
+        // copy the src? nodes
+        nvPairs.clear();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_COPY));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Copy Success");
+
+        // assert content test
+        String content2 = getContent(HTTP_BASE_URL + testPath
+            + "/dest/src1.json", CONTENT_TYPE_JSON);
+        JSONObject json2 = new JSONObject(content2);
+        assertEquals("Modified Hello", json2.get("text"));
+
+        // clean up
+        testClient.delete(testRoot);
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletCreateTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletCreateTest.java
new file mode 100644
index 0000000..b6ed3aa
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletCreateTest.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test node creation via the MicrojaxPostServlet */
+public class PostServletCreateTest extends HttpTestBase {
+    public static final String TEST_BASE_PATH = "/sling-tests";
+    private String postUrl;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+    }
+
+   public void testPostPathIsUnique() throws IOException {
+        assertHttpStatus(postUrl, HttpServletResponse.SC_NOT_FOUND,
+                "Path must not exist before test: " + postUrl);
+    }
+
+    public void testCreateNode() throws IOException {
+        final String location = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
+        assertHttpStatus(location + DEFAULT_EXT, HttpServletResponse.SC_OK,
+                "POST must redirect to created resource (" + location + ")");
+        assertTrue("Node (" + location + ") must have generated name",
+                !location.endsWith("/*"));
+        assertTrue("Node (" + location + ") must created be under POST URL (" + postUrl + ")",
+                location.contains(postUrl + "/"));
+    }
+
+    public void testCreateNodeWithExtension() throws IOException {
+        final String location = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX + ".html", null);
+        assertHttpStatus(location + DEFAULT_EXT, HttpServletResponse.SC_OK,
+                "POST must redirect to created resource (" + location + ")");
+        assertTrue("Node (" + location + ") must have generated name",
+                !location.endsWith("/*"));
+        assertTrue("Node (" + location + ") must created be under POST URL (" + postUrl + ")",
+                location.contains(postUrl + "/"));
+    }
+
+    public void testCreateNodeAtSpecificUrl() throws IOException {
+        final String specifiedLocation = postUrl + "/specified-location";
+        final String location = testClient.createNode(specifiedLocation, null);
+        assertHttpStatus(location + DEFAULT_EXT, HttpServletResponse.SC_OK,
+                "POST must redirect to created resource (" + location + ")");
+        assertTrue("Node (" + location + ") must be created at given URL (" + specifiedLocation + ")",
+                location.equals(specifiedLocation));
+    }
+
+    public void testCreateNodeAtDeepUrl() throws IOException {
+        final long id = System.currentTimeMillis();
+        final String specifiedLocation = postUrl + "/specified-location" + id + "/deepA/deepB/" + id;
+        final String location = testClient.createNode(specifiedLocation, null);
+        assertHttpStatus(location + DEFAULT_EXT, HttpServletResponse.SC_OK,
+                "POST must redirect to created resource (" + location + ")");
+        assertTrue("Node (" + location + ") must be created (deep) at given URL (" + specifiedLocation + ")",
+                location.equals(specifiedLocation));
+    }
+
+    /** Create a node with some data, and check that data */
+    public void testCreateWithData() throws IOException {
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("a","123");
+        props.put("b","456");
+        props.put("c","some words");
+        final String createdNodeUrl = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        final String content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+        assertJavascript("123456", content, "out.println(data.a + data.b)");
+        assertJavascript("some words", content, "out.println(data.c)");
+    }
+
+    /** Create a node with a propery in a subnode, and check (SLING-223) */
+    public void testCreateSubnodeProperty() throws IOException {
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("a","123");
+        props.put("subnode/b","456");
+        props.put("c","some words");
+        final String createdNodeUrl = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        final String content = getContent(createdNodeUrl + ".2.json", CONTENT_TYPE_JSON);
+        assertJavascript("123", content, "out.println(data.a)");
+        assertJavascript("456", content, "out.println(data.subnode.b)");
+        assertJavascript("some words", content, "out.println(data.c)");
+    }
+
+    /** Use the default "save prefix" on some parameters, and check that only those
+     *  who have the prefix are saved.
+     */
+    public void testDefaultSavePrefix() throws IOException {
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("./a","123");
+        props.put("./b","456");
+        props.put("c","not saved");
+        final String createdNodeUrl = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        final String content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+        assertJavascript("123456", content, "out.println(data.a + data.b)");
+        assertJavascript("undefined", content, "out.println(typeof data.c)");
+    }
+
+    /** SLING-394 removed :saveParamPrefix support. We check whether this is
+     * really ignored
+     */
+    public void testCustomSavePrefix() throws IOException {
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("STUFF_a","123");
+        props.put("STUFF_b","456");
+        props.put("c","not saved");
+        props.put(":saveParamPrefix","STUFF_");
+        final String createdNodeUrl = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props,null,false);
+        final String content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+        assertJavascript("undefined", content, "out.println(typeof data.a)");
+        assertJavascript("undefined", content, "out.println(typeof data.b)");
+        assertJavascript("123456", content, "out.println(data.STUFF_a + data.STUFF_b)");
+        assertJavascript("string", content, "out.println(typeof data.c)");
+    }
+
+ }
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletDeleteTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletDeleteTest.java
new file mode 100644
index 0000000..b627886
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletDeleteTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test node deletion via the MicrojaxPostServlet */
+public class PostServletDeleteTest extends HttpTestBase {
+    public static final String TEST_BASE_PATH = "/sling-tests";
+    private String postUrl;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + getClass().getSimpleName() + "/" + System.currentTimeMillis();
+
+        assertHttpStatus(postUrl, HttpServletResponse.SC_NOT_FOUND,
+                "Path must not exist before test: " + postUrl);
+    }
+
+    public void testDelete() throws IOException {
+        final String urlA = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
+        final String urlB = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
+        final String urlC = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
+        final String urlD = testClient.createNode(postUrl + "/specific-location/for-delete", null);
+        
+        // initially all nodes must be found
+        assertHttpStatus(urlA + DEFAULT_EXT, HttpServletResponse.SC_OK, "A must initially exist");
+        assertHttpStatus(urlB + DEFAULT_EXT, HttpServletResponse.SC_OK, "B must initially exist");
+        assertHttpStatus(urlC + DEFAULT_EXT, HttpServletResponse.SC_OK, "C must initially exist");
+        assertHttpStatus(urlD + DEFAULT_EXT, HttpServletResponse.SC_OK, "D must initially exist");
+        
+        // delete one and check
+        final List <NameValuePair> params = new LinkedList<NameValuePair> ();
+        params.add(new NameValuePair(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_DELETE));
+        assertPostStatus(urlA,HttpServletResponse.SC_OK,params,"Delete must return expected status (3)");
+        assertHttpStatus(urlA + DEFAULT_EXT, HttpServletResponse.SC_NOT_FOUND, "A must be deleted (1)");
+        assertHttpStatus(urlB + DEFAULT_EXT, HttpServletResponse.SC_OK, "B must still exist");
+        assertHttpStatus(urlC + DEFAULT_EXT, HttpServletResponse.SC_OK, "C must still exist");
+        assertHttpStatus(urlD + DEFAULT_EXT, HttpServletResponse.SC_OK, "D must still exist");
+        
+        // delete the others with successive requests
+        assertPostStatus(urlB,HttpServletResponse.SC_OK,params,"Delete must return expected status (2)");
+        assertPostStatus(urlC,HttpServletResponse.SC_OK,params,"Delete must return expected status (2)");
+        assertPostStatus(urlD,HttpServletResponse.SC_OK,params,"Delete must return expected status (2)");
+        assertHttpStatus(urlA + DEFAULT_EXT, HttpServletResponse.SC_NOT_FOUND, "A must be deleted (2)");
+        assertHttpStatus(urlB + DEFAULT_EXT, HttpServletResponse.SC_NOT_FOUND, "B must be deleted (2)");
+        assertHttpStatus(urlC + DEFAULT_EXT, HttpServletResponse.SC_NOT_FOUND, "C must be deleted (2)");
+        assertHttpStatus(urlD + DEFAULT_EXT, HttpServletResponse.SC_NOT_FOUND, "D must be deleted (2)");
+        
+        // attempting to delete non-existing nodes is ok
+        assertPostStatus(postUrl,HttpServletResponse.SC_OK,params,"Delete must return expected status (2)");
+    }
+
+    public void testDeleteMultiple() throws IOException {
+        final String urlA = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
+        final String urlB = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
+        final String urlC = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, null);
+        final String urlD = testClient.createNode(postUrl + "/specific-location/for-delete", null);
+
+        // initially all nodes must be found
+        assertHttpStatus(urlA + DEFAULT_EXT, HttpServletResponse.SC_OK, "A must initially exist");
+        assertHttpStatus(urlB + DEFAULT_EXT, HttpServletResponse.SC_OK, "B must initially exist");
+        assertHttpStatus(urlC + DEFAULT_EXT, HttpServletResponse.SC_OK, "C must initially exist");
+        assertHttpStatus(urlD + DEFAULT_EXT, HttpServletResponse.SC_OK, "D must initially exist");
+
+        // delete one and check
+        final List <NameValuePair> params = new LinkedList<NameValuePair> ();
+        params.add(new NameValuePair(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_DELETE));
+        params.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, urlA.substring(HTTP_BASE_URL.length())));
+        params.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, urlB.substring(HTTP_BASE_URL.length())));
+        assertPostStatus(urlC,HttpServletResponse.SC_OK,params,"Delete must return expected status (3)");
+        assertHttpStatus(urlA + DEFAULT_EXT, HttpServletResponse.SC_NOT_FOUND, "A must be deleted (1)");
+        assertHttpStatus(urlB + DEFAULT_EXT, HttpServletResponse.SC_NOT_FOUND, "B must be deleted (1)");
+        assertHttpStatus(urlC + DEFAULT_EXT, HttpServletResponse.SC_OK, "C must still exist");
+        assertHttpStatus(urlD + DEFAULT_EXT, HttpServletResponse.SC_OK, "D must still exist");
+
+        // delete the others with successive requests
+        params.clear();
+        params.add(new NameValuePair(SlingPostConstants.RP_OPERATION, SlingPostConstants.OPERATION_DELETE));
+        params.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, urlA.substring(HTTP_BASE_URL.length())));
+        params.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, urlB.substring(HTTP_BASE_URL.length())));
+        params.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, urlC.substring(HTTP_BASE_URL.length())));
+        params.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, urlD.substring(HTTP_BASE_URL.length())));
+        assertPostStatus(urlC,HttpServletResponse.SC_OK,params,"Delete must return expected status (3)");
+        assertHttpStatus(urlA + DEFAULT_EXT, HttpServletResponse.SC_NOT_FOUND, "A must be deleted (2)");
+        assertHttpStatus(urlB + DEFAULT_EXT, HttpServletResponse.SC_NOT_FOUND, "B must be deleted (2)");
+        assertHttpStatus(urlC + DEFAULT_EXT, HttpServletResponse.SC_NOT_FOUND, "C must be deleted (2)");
+        assertHttpStatus(urlD + DEFAULT_EXT, HttpServletResponse.SC_NOT_FOUND, "D must be deleted (2)");
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletMoveTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletMoveTest.java
new file mode 100644
index 0000000..be993ef
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletMoveTest.java
@@ -0,0 +1,476 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.commons.testing.integration.HttpStatusCodeException;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test node move via the MicrojaxPostServlet */
+public class PostServletMoveTest extends HttpTestBase {
+
+    public static final String TEST_BASE_PATH = "/sling-move-tests";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public void testMoveNodeAbsolute() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/abs/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE);
+        props.put(SlingPostConstants.RP_DEST, testPath + "/dest");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+
+        // assert no content at old location
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src.json",
+            HttpServletResponse.SC_NOT_FOUND,
+            "Expected Not_Found for old content");
+    }
+
+    public void testMoveNodeAbsoluteBelowDest() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/abs/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // first test: failure because dest (parent) does not exist
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        assertPostStatus(HTTP_BASE_URL + testPath + "/src",
+            HttpServletResponse.SC_PRECONDITION_FAILED, nvPairs,
+            "Expecting Move Failure (dest must exist)");
+
+        // create dest as parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", null);
+
+        // move now succeeds to below dest
+        assertPostStatus(HTTP_BASE_URL + testPath + "/src",
+            HttpServletResponse.SC_CREATED, nvPairs, "Expecting Move Success");
+
+        // assert content at new location
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.-1.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.src.text)");
+
+        // assert content at old location
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src.json",
+            HttpServletResponse.SC_NOT_FOUND);
+    }
+
+    public void testMoveNodeRelative() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/rel/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE);
+        props.put(SlingPostConstants.RP_DEST, "dest");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+    }
+
+    public void testMoveNodeExistingFail() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/exist/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // create dest node
+        props.put("text", "Hello Destination");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE);
+        props.put(SlingPostConstants.RP_DEST, testPath + "/dest");
+        try {
+            testClient.createNode(HTTP_BASE_URL + testPath, props);
+        } catch (HttpStatusCodeException hsce) {
+            // if we do not get the status code 302 message, fail
+            if (hsce.getActualStatus() == 302) {
+                throw hsce;
+            }
+        }
+
+        // expect unmodified dest
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello Destination", content, "out.println(data.text)");
+    }
+
+    public void testMoveNodeExistingReplace() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/replace/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        // create dest node
+        props.put("text", "Hello Destination");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE);
+        props.put(SlingPostConstants.RP_DEST, testPath + "/dest");
+        props.put(SlingPostConstants.RP_REPLACE, "true");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+        String content = getContent(HTTP_BASE_URL + testPath + "/dest.json",
+            CONTENT_TYPE_JSON);
+        assertJavascript("Hello", content, "out.println(data.text)");
+    }
+
+    public void testMoveNodeDeepRelative() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/new/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE);
+        props.put(SlingPostConstants.RP_DEST, "deep/new");
+
+        try {
+            testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+            fail("Moving node to non existing parent location should fail.");
+        } catch (HttpStatusCodeException hsce) {
+            // actually the status is not 200, but we get "browser" clear stati
+            if (hsce.getActualStatus() != 200) {
+                throw hsce;
+            }
+        }
+    }
+
+    public void testMoveNodeDeepAbsolute() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/new_fail/"
+            + System.currentTimeMillis();
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src", props);
+
+        props.clear();
+        props.put(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE);
+        props.put(SlingPostConstants.RP_DEST, "/some/not/existing/structure");
+        try {
+            testClient.createNode(HTTP_BASE_URL + testPath + "/*", props);
+            // not quite correct. should check status response
+            fail("Moving node to non existing parent location should fail.");
+        } catch (HttpStatusCodeException hsce) {
+            // actually the status is not 200, but we get "browser" clear stati
+            if (hsce.getActualStatus() != 200) {
+                throw hsce;
+            }
+        }
+    }
+
+    public void testMoveNodeMultipleSourceValid() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/mvmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src2", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src3", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src4", props);
+
+        // move the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src3"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src4"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Move Failure: dest parent does not exist");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // now dest exists, so we expect success
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Move Success");
+
+        // assert existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_OK);
+
+        // assert non-existence of src?
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src1.html",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src2.html",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src3.html",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src4.html",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        testClient.delete(testRoot);
+    }
+
+    public void testMoveNodeMultipleSourceInValid() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/mvmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src2", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src3", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src4", props);
+
+        // move the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src3"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src4"));
+        assertPostStatus(testRoot,
+            HttpServletResponse.SC_INTERNAL_SERVER_ERROR, nvPairs,
+            "Expecting Move Failure (dest must have trailing slash)");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // retest after creating test
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Move Failure (dest already exists)");
+
+        // assert non-existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        // assert non-existence of src?
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src1.html",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src2.html",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src3.html",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src4.html",
+            HttpServletResponse.SC_OK);
+
+        testClient.delete(testRoot);
+    }
+
+    public void testMoveNodeMultipleSourcePartial() throws IOException {
+        final String testPath = TEST_BASE_PATH + "/mvmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src3", props);
+
+        // move the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src3"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src4"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Move Failure: dest parent does not exist");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", props);
+
+        // now dest exists, so we expect success
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Move Success");
+
+        // assert partial existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        // assert non-existence of src?
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src1.html",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src2.html",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src3.html",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/src4.html",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        testClient.delete(testRoot);
+    }
+
+    public void testMoveNodeMultipleSourceReplace() throws Exception {
+        final String testPath = TEST_BASE_PATH + "/mvmult/"
+            + System.currentTimeMillis();
+        final String testRoot = testClient.createNode(HTTP_BASE_URL + testPath,
+            null);
+
+        // create multiple source nodes
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("text", "Hello");
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src1", props);
+        testClient.createNode(HTTP_BASE_URL + testPath + "/src2", props);
+
+        // move the src? nodes
+        List<NameValuePair> nvPairs = new ArrayList<NameValuePair>();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_PRECONDITION_FAILED,
+            nvPairs, "Expecting Move Failure: dest parent does not exist");
+
+        // create destination parent
+        testClient.createNode(HTTP_BASE_URL + testPath + "/dest", null);
+
+        // now dest exists, so we expect success
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Move Success");
+
+        // assert partial existence of the src?/text properties
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src1/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src2/text",
+            HttpServletResponse.SC_OK);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src3/text",
+            HttpServletResponse.SC_NOT_FOUND);
+        assertHttpStatus(HTTP_BASE_URL + testPath + "/dest/src4/text",
+            HttpServletResponse.SC_NOT_FOUND);
+
+        // assert content test
+        String content = getContent(HTTP_BASE_URL + testPath
+            + "/dest/src1.json", CONTENT_TYPE_JSON);
+        JSONObject json = new JSONObject(content);
+        assertEquals("Hello", json.get("text"));
+
+        // modify src1 content
+        nvPairs.clear();
+        nvPairs.add(new NameValuePair("text", "Modified Hello"));
+        assertPostStatus(HTTP_BASE_URL + testPath + "/src1",
+            HttpServletResponse.SC_CREATED, nvPairs,
+            "Expect Content Create Success");
+
+        // move the src? nodes
+        nvPairs.clear();
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_OPERATION,
+            SlingPostConstants.OPERATION_MOVE));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_DEST, testPath
+            + "/dest/"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src1"));
+        nvPairs.add(new NameValuePair(SlingPostConstants.RP_APPLY_TO, testPath
+            + "/src2"));
+        assertPostStatus(testRoot, HttpServletResponse.SC_OK, nvPairs,
+            "Expecting Move Success");
+
+        // assert content test
+        String content2 = getContent(HTTP_BASE_URL + testPath
+            + "/dest/src1.json", CONTENT_TYPE_JSON);
+        JSONObject json2 = new JSONObject(content2);
+        assertEquals("Modified Hello", json2.get("text"));
+
+        // clean up
+        testClient.delete(testRoot);
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletNopTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletNopTest.java
new file mode 100644
index 0000000..ac13581
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletNopTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+
+public class PostServletNopTest extends HttpTestBase {
+
+    private static final String TEST_URL = HTTP_BASE_URL + "/"
+        + System.currentTimeMillis();
+
+    public void testDefault() throws IOException {
+        post(TEST_URL, null, 200);
+    }
+
+    public void testStatus200() throws IOException {
+        post(TEST_URL, 200);
+    }
+
+    public void testStatus708() throws IOException {
+        post(TEST_URL, 708);
+    }
+
+    // request status <100, expect default 200
+    public void testStatus88() throws IOException {
+        post(TEST_URL, "88", 200);
+    }
+
+    // request status >999, expect default 200
+    public void testStatus1234() throws IOException {
+        post(TEST_URL, "1234", 200);
+    }
+
+    // request non-numeric status, expect default 200
+    public void testStatusNonNumeric() throws IOException {
+        post(TEST_URL, "nonumber", 200);
+    }
+
+    private void post(String url, int status) throws IOException {
+        post(url, String.valueOf(status), status);
+    }
+
+    private void post(String url, String code, int expectedStatus)
+            throws IOException {
+        final PostMethod post = new PostMethod(url);
+        post.setFollowRedirects(false);
+
+        post.addParameter(":operation", "nop");
+
+        if (code != null) {
+            post.addParameter(":nopstatus", code);
+        }
+
+        int actualStatus = httpClient.executeMethod(post);
+        assertEquals(expectedStatus, actualStatus);
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletOrderTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletOrderTest.java
new file mode 100644
index 0000000..e875619
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletOrderTest.java
@@ -0,0 +1,209 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+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.testing.integration.HttpTestBase;
+
+/** Test the order option for node creation via the MicrojaxPostServlet */
+public class PostServletOrderTest extends HttpTestBase {
+
+    public static final String TEST_BASE_PATH = "/sling-tests-order";
+
+    private static final String[] DEFAULT_ORDER = new String[]{"a","b","c","d"};
+
+    /*
+        does not work (yet) since rhino does not preserve order of
+        object elements.
+
+    private static final String TEST_SCRIPT =
+            "var s=''; " +
+            "for (var a in data) {" +
+            "   var n = data[a];" +
+            "   if (typeof(n) == 'object') s += a + ',';" +
+            "}" +
+            "out.println(s);";
+     */
+
+    /**
+     * Create nodes and check if they are in default order
+     */
+    public void testStandardOrder() throws IOException {
+        final String postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+        createNodes(postUrl, DEFAULT_ORDER);
+        verifyOrder(postUrl, DEFAULT_ORDER);
+    }
+
+    /**
+     * Create nodes and check if they are in correct order after a
+     * :order="first" request
+     */
+    public void testOrderFirst() throws IOException {
+        final String postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+        createNodes(postUrl, DEFAULT_ORDER);
+
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put(":order","first");
+        testClient.createNode(postUrl + "/c", props);
+        verifyOrder(postUrl, new String[]{"c", "a", "b", "d"});
+    }
+
+    /**
+     * Create nodes and check if they are in correct order after a
+     * :order="last" request
+     */
+    public void testOrderLast() throws IOException {
+        final String postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+        createNodes(postUrl, DEFAULT_ORDER);
+
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put(":order","last");
+        testClient.createNode(postUrl + "/c", props);
+        verifyOrder(postUrl, new String[]{"a", "b", "d", "c"});
+    }
+
+    /**
+     * Create nodes and check if they are in correct order after a
+     * :order="before" request
+     */
+    public void testOrderBefore() throws IOException {
+        final String postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+        createNodes(postUrl, DEFAULT_ORDER);
+
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put(":order","before b");
+        testClient.createNode(postUrl + "/c", props);
+        verifyOrder(postUrl, new String[]{"a", "c", "b", "d"});
+    }
+
+    /**
+     * Create nodes and check if they are in correct order after a
+     * :order="after" request
+     */
+    public void testOrderAfter() throws IOException {
+        final String postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+        createNodes(postUrl, DEFAULT_ORDER);
+
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put(":order","after c");
+        testClient.createNode(postUrl + "/b", props);
+        verifyOrder(postUrl, new String[]{"a", "c", "b", "d"});
+    }
+
+    /**
+     * Create nodes and check if they are in correct order after a
+     * :order="N" request, where new position is greater than old one.
+     */
+    public void testOrderIntToBack() throws IOException {
+        final String postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+        createNodes(postUrl, DEFAULT_ORDER);
+
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put(":order","2");
+        testClient.createNode(postUrl + "/a", props);
+        verifyOrder(postUrl, new String[]{"b", "c", "a", "d"});
+    }
+
+    /**
+     * Create nodes and check if they are in correct order after a
+     * :order="N" request, where new position is less than old one.
+     */
+    public void testOrderIntToFront() throws IOException {
+        final String postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+        createNodes(postUrl, DEFAULT_ORDER);
+
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put(":order","1");
+        testClient.createNode(postUrl + "/d", props);
+        verifyOrder(postUrl, new String[]{"a", "d", "b", "c"});
+    }
+
+    /**
+     * Create nodes and check if they are in correct order after a
+     * :order="0" request
+     */
+    public void testOrderIntZero() throws IOException {
+        final String postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+        createNodes(postUrl, DEFAULT_ORDER);
+
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put(":order","0");
+        testClient.createNode(postUrl + "/d", props);
+        verifyOrder(postUrl, new String[]{"d", "a", "b", "c"});
+    }
+
+    /**
+     * Create nodes and check if they are in correct order after a
+     * :order="N" request, where new position is out of bounds
+     */
+    public void testOrderIntOOB() throws IOException {
+        final String postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+        createNodes(postUrl, DEFAULT_ORDER);
+
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put(":order","100");
+        testClient.createNode(postUrl + "/a", props);
+        verifyOrder(postUrl, new String[]{"b", "c", "d", "a"});
+    }
+
+    /**
+     * Create test nodes
+     */
+    private String[] createNodes(String parentUrl, String[] names)
+            throws IOException {
+        String[] urls = new String[names.length];
+        for (int i=0; i<names.length; i++) {
+            urls[i] = testClient.createNode(parentUrl + "/" + names[i], null);
+        }
+        return urls;
+    }
+
+    /**
+     * Verify node order
+     */
+    private void verifyOrder(String parentUrl, String[] names)
+            throws IOException {
+        // check that nodes appear in creation order in their parent's list of children
+        final String content = getContent(parentUrl + ".1.json", CONTENT_TYPE_JSON);
+        String expected = "";
+        for (String n: names) {
+            expected +=n + ",";
+        }
+        //assertJavascript(expected, content, TEST_SCRIPT);
+        try {
+            String actual = "";
+            JSONObject obj = new JSONObject(content);
+            JSONArray n = obj.names();
+            for (int i=0; i<n.length(); i++) {
+                String name = n.getString(i);
+                Object o = obj.get(name);
+                if (o instanceof JSONObject) {
+                    actual += name + ",";
+                }
+            }
+            assertEquals(expected, actual);
+        } catch (JSONException e) {
+            throw new IOException(e.toString());
+        }
+    }
+ }
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletUpdateTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletUpdateTest.java
new file mode 100644
index 0000000..146a86d
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostServletUpdateTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+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.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test node updates via the MicrojaxPostServlet */
+public class PostServletUpdateTest extends HttpTestBase {
+    public static final String TEST_BASE_PATH = "/sling-tests";
+    private String postUrl;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+    }
+
+   public void testPostPathIsUnique() throws IOException {
+        assertHttpStatus(postUrl, HttpServletResponse.SC_NOT_FOUND,
+                "Path must not exist before test: " + postUrl);
+    }
+
+    public void testUpdateWithChanges() throws IOException {
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("./a","123");
+        props.put("./b","456");
+
+        final String location = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        String content = getContent(location + ".json", CONTENT_TYPE_JSON);
+        assertJavascript("123456", content, "out.println(data.a + data.b)");
+
+        props.put("./a","789");
+        // the testClient method is called createNode but all it does is a POST,
+        // so it can be used for updates as well
+        final String newLocation = testClient.createNode(location, props);
+        assertEquals("Location must not changed after POST to existing node",location,newLocation);
+        content = getContent(location + ".json", CONTENT_TYPE_JSON);
+        assertJavascript("789456", content, "out.println(data.a + data.b)");
+    }
+
+    public void testUpdateNoChanges() throws IOException {
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("./a","123");
+        props.put("./b","456");
+
+        final String location = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        String content = getContent(location + ".json", CONTENT_TYPE_JSON);
+        assertJavascript("123456", content, "out.println(data.a + data.b)");
+
+        props.clear();
+        // the testClient method is called createNode but all it does is a POST,
+        // so it can be used for updates as well
+        final String newLocation = testClient.createNode(location, props);
+        assertEquals("Location must not changed after POST to existing node",location,newLocation);
+        content = getContent(location + ".json", CONTENT_TYPE_JSON);
+        assertJavascript("123456", content, "out.println(data.a + data.b)");
+    }
+
+    public void testUpdateSomeChanges() throws IOException {
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("./a","123");
+        props.put("./b","456");
+        props.put("C","not stored");
+
+        final String location = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        String content = getContent(location + ".json", CONTENT_TYPE_JSON);
+        assertJavascript("123456", content, "out.println(data.a + data.b)");
+
+        props.clear();
+        props.put("./b","457");
+        props.put("C","still not stored");
+
+        // the testClient method is called createNode but all it does is a POST,
+        // so it can be used for updates as well
+        final String newLocation = testClient.createNode(location, props);
+        assertEquals("Location must not changed after POST to existing node",location,newLocation);
+        content = getContent(location + ".json", CONTENT_TYPE_JSON);
+        assertJavascript("123457", content, "out.println(data.a + data.b)");
+    }
+
+    public void testMultivalueHint() throws IOException {
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("./f","123");
+        props.put("./f@TypeHint", "String[]");
+        props.put("./g","456");
+
+        final String location = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        String content = getContent(location + ".json", CONTENT_TYPE_JSON);
+        assertTrue(content.indexOf("\"f\":[\"123\"]") > 0);
+        assertTrue(content.indexOf("\"g\":\"456\"") > 0);
+    }
+
+    public void testMixinTypes() throws IOException, JSONException {
+        
+        // create a node without mixin node types
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("jcr:primaryType","nt:unstructured");
+        final String location = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        
+        // assert no mixins
+        String content = getContent(location + ".json", CONTENT_TYPE_JSON);
+        JSONObject json = new JSONObject(content);
+        assertFalse("jcr:mixinTypes not expected to be set", json.has("jcr:mixinTypes"));
+        
+        // add mixin
+        props.clear();
+        props.put("jcr:mixinTypes", "mix:versionable");
+        testClient.createNode(location, props);
+        
+        content = getContent(location + ".json", CONTENT_TYPE_JSON);
+        json = new JSONObject(content);
+        assertTrue("jcr:mixinTypes expected after setting them", json.has("jcr:mixinTypes"));
+        
+        Object mixObject = json.get("jcr:mixinTypes");
+        assertTrue("jcr:mixinTypes must be an array", mixObject instanceof JSONArray);
+        
+        JSONArray mix = (JSONArray) mixObject;
+        assertTrue("jcr:mixinTypes must have a single entry", mix.length() == 1);
+        assertEquals("jcr:mixinTypes must have correct value", "mix:versionable", mix.get(0));
+
+        // remove mixin
+        props.clear();
+        props.put("jcr:mixinTypes@Delete", "-");
+        testClient.createNode(location, props);
+
+        content = getContent(location + ".json", CONTENT_TYPE_JSON);
+        json = new JSONObject(content);
+        assertTrue("no jcr:mixinTypes expected after clearing it", !json.has("jcr:mixinTypes"));
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostStatusTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostStatusTest.java
new file mode 100644
index 0000000..a8304a5
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostStatusTest.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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** Test the various status options for POST, SLING-422 */
+public class PostStatusTest extends HttpTestBase {
+
+    private String postPath = "PostStatusTest/" + System.currentTimeMillis();
+
+    public void testStandardStatusNull() throws IOException {
+        final String resPath = "/" + postPath + "/StandardNull";
+        final String postUrl = HTTP_BASE_URL + resPath;
+        simplePost(postUrl, null, 201, resPath);
+    }
+    
+    public void testStandardStatusStandard() throws IOException {
+        final String resPath = "/" + postPath + "/StandardStandard";
+        final String postUrl = HTTP_BASE_URL + resPath;
+        simplePost(postUrl, SlingPostConstants.STATUS_VALUE_STANDARD, 201, resPath);
+    }
+    
+    public void testStandardStatusUnknown() throws IOException {
+        final String resPath = "/" + postPath + "/StandardUnknown";
+        final String postUrl = HTTP_BASE_URL + resPath;
+        simplePost(postUrl, "Unknown Value", 201, resPath);
+    }
+    
+    public void testStatusBrowser() throws IOException {
+        final String resPath = "/" + postPath + "/Browser";
+        final String postUrl = HTTP_BASE_URL + resPath;
+        simplePost(postUrl, SlingPostConstants.STATUS_VALUE_BROWSER, 200, null);
+    }
+
+    private void simplePost(String url, String statusParam, int expectStatus,
+            String expectLocation) throws IOException {
+
+        final PostMethod post = new PostMethod(url);
+        post.setFollowRedirects(false);
+
+        if (statusParam != null) {
+            post.addParameter(SlingPostConstants.RP_STATUS, statusParam);
+        }
+
+        final int status = httpClient.executeMethod(post);
+        assertEquals("Unexpected status response", expectStatus, status);
+
+        if (expectLocation != null) {
+            String location = post.getResponseHeader("Location").getValue();
+
+            assertNotNull("Expected location header", location);
+            assertTrue(location.endsWith(expectLocation));
+        }
+
+        post.releaseConnection();
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostToRootTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostToRootTest.java
new file mode 100644
index 0000000..6945c1e
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/PostToRootTest.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The 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.launchpad.webapp.integrationtest.servlets.post;
+
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/** Test POSTing to root node (SLING-668) */
+public class PostToRootTest extends HttpTestBase {
+	
+	public void testSetRootProperty() throws Exception {
+		String url = HTTP_BASE_URL;
+		if(!url.endsWith("/")) {
+			url += "/";
+		}
+        final PostMethod post = new PostMethod(url);
+		final String name = getClass().getSimpleName();
+		final String value = getClass().getSimpleName() + System.currentTimeMillis();
+		post.addParameter(name, value);
+		
+		final int status = httpClient.executeMethod(post);
+		assertEquals(200, status);
+		
+		final String json = getContent(url + ".json", CONTENT_TYPE_JSON);
+		assertJavascript(value, json, "out.print(data." + name + ")");
+	}
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/SlingAutoPropertiesTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/SlingAutoPropertiesTest.java
new file mode 100644
index 0000000..86a6a9f
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/SlingAutoPropertiesTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** {#link MicrojaxPropertyValueSetter} sets the value of some properties
+ *  automatically if they are empty. This is tested here with various cases.
+ */
+
+public class SlingAutoPropertiesTest extends HttpTestBase {
+
+    public static final String TEST_BASE_PATH = "/sling-tests";
+    private String postUrl;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+    }
+
+   public void testPostPathIsUnique() throws IOException {
+        assertHttpStatus(postUrl, HttpServletResponse.SC_NOT_FOUND,
+                "Path must not exist before test: " + postUrl);
+    }
+
+    public void testCreatedAndModified() throws IOException {
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("a","123");
+
+        props.put("created","");
+        props.put("createdBy","");
+        props.put("lastModified","");
+        props.put("lastModifiedBy","");
+
+        final String createdNodeUrl = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        String content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+
+        assertJavascript("123", content, "out.println(data.a)");
+        assertJavascript("admin", content, "out.println(data.createdBy)");
+        assertJavascript("admin", content, "out.println(data.lastModifiedBy)");
+        assertJavascript("true", content, "out.println(data.created.length > 0)");
+        assertJavascript("true", content, "out.println(data.lastModified.length > 0)");
+        assertJavascript("true", content, "out.println(data.lastModified == data.created)");
+
+        // update node and check that "last modified" has changed
+        try {
+            Thread.sleep(1000L);
+        } catch(InterruptedException ignored) {
+            // ignore
+        }
+
+        testClient.createNode(createdNodeUrl, props);
+        content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+
+        assertJavascript("123", content, "out.println(data.a)");
+        assertJavascript("admin", content, "out.println(data.createdBy)");
+        assertJavascript("admin", content, "out.println(data.lastModifiedBy)");
+        assertJavascript("true", content, "out.println(data.created.length > 0)");
+        assertJavascript("true", content, "out.println(data.lastModified.length > 0)");
+        assertJavascript("true", content, "out.println(data.lastModified > data.created)");
+    }
+
+    public void testWithSpecificValues() throws IOException {
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("a","123");
+
+        props.put("created","a");
+        props.put("createdBy","b");
+        props.put("lastModified","c");
+        props.put("lastModifiedBy","d");
+
+        final String createdNodeUrl = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        final String content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+
+        assertJavascript("123", content, "out.println(data.a)");
+        assertJavascript("a", content, "out.println(data.created)");
+        assertJavascript("b", content, "out.println(data.createdBy)");
+        assertJavascript("c", content, "out.println(data.lastModified)");
+        assertJavascript("d", content, "out.println(data.lastModifiedBy)");
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/SlingDateValuesTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/SlingDateValuesTest.java
new file mode 100644
index 0000000..fdb8bd6
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/SlingDateValuesTest.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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/**
+ *  checks if the date parsing for non jcr-dates works.
+ */
+
+public class SlingDateValuesTest extends HttpTestBase {
+
+    public static final String TEST_BASE_PATH = "/sling-tests";
+
+    // TODO: the commented formats do not work beacuse of SLING-242
+    //       the + of the timezone offset is stripped by sling
+
+    private final SimpleDateFormat[] testFormats = new SimpleDateFormat[]{
+        new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'Z", Locale.US),
+        new SimpleDateFormat("dd.MM.yyyy HH:mm:ss", Locale.US),
+        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US),
+        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US)
+    };
+
+    private String postUrl;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+    }
+
+    private void doDateTest(String expected, String input)
+            throws IOException {
+        final Map<String, String> props = new HashMap<String, String>();
+        props.put("someDate", input);
+        props.put("someDate@TypeHint", "Date");
+
+        final String createdNodeUrl = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        String content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+
+        // default behaviour writes empty string
+        assertJavascript(expected, content, "out.println(data.someDate)");
+    }
+
+    public void testDateValues() throws IOException {
+        SimpleDateFormat ecmaFmt = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'Z", Locale.US);
+        Date now = new Date();
+        String nowStr = ecmaFmt.format(now);
+        for (SimpleDateFormat fmt: testFormats) {
+            String testStr = fmt.format(now);
+            doDateTest(nowStr, testStr);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/SlingDefaultValuesTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/SlingDefaultValuesTest.java
new file mode 100644
index 0000000..af84982
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/SlingDefaultValuesTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/** {#link SlingPropertyValueSetter} sets the value of some properties
+ *  with default values if they are empty. This is tested here with various cases.
+ */
+
+public class SlingDefaultValuesTest extends HttpTestBase {
+
+    public static final String TEST_BASE_PATH = "/sling-tests";
+    private String postUrl;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+    }
+
+    public void testDefaultBehaviour() throws IOException {
+        final Map<String, String> props = new HashMap<String, String>();
+        props.put("a","");
+
+        final String createdNodeUrl = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        String content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+
+        // default behaviour writes empty string
+        assertJavascript("undefined", content, "out.println(\"\" + data.a)");
+
+        // overwrite with "123"
+        props.put("a", "123");
+        testClient.createNode(createdNodeUrl, props);
+        content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+
+        assertJavascript("123", content, "out.println(data.a)");
+
+        // and clear again
+        props.put("a", "");
+        testClient.createNode(createdNodeUrl, props);
+        content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+
+        assertJavascript("undefined", content, "out.println(\"\" + data.a)");
+    }
+
+    public void testWithSpecificDefault() throws IOException {
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("a","");
+        props.put("a@DefaultValue","123");
+
+        final String createdNodeUrl = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        final String content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+
+        assertJavascript("123", content, "out.println(data.a)");
+    }
+
+    public void testWithIgnore() throws IOException {
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("a","");
+        props.put("a@DefaultValue",":ignore");
+
+        final String createdNodeUrl = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        final String content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+
+        assertJavascript("undefined", content, "out.println(typeof(data.a))");
+    }
+
+    public void testWithNull() throws IOException {
+        final Map <String, String> props = new HashMap <String, String> ();
+        props.put("a","123");
+
+        final String createdNodeUrl = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, props);
+        String content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+
+        assertJavascript("123", content, "out.println(data.a)");
+
+        // now try to delete prop by sending empty string
+        props.put("a","");
+        props.put("a@DefaultValue",":null");
+        testClient.createNode(createdNodeUrl, props);
+        content = getContent(createdNodeUrl + ".json", CONTENT_TYPE_JSON);
+
+        assertJavascript("undefined", content, "out.println(typeof(data.a))");
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/SlingSessionInfoTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/SlingSessionInfoTest.java
new file mode 100644
index 0000000..2cb6738
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/post/SlingSessionInfoTest.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The 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.launchpad.webapp.integrationtest.servlets.post;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/** Test the sling:sessionInfo resource */
+
+public class SlingSessionInfoTest extends HttpTestBase {
+
+    public void testSessionInfo() throws IOException {
+        final String content = getContent(HTTP_BASE_URL + "/system/sling/info.sessionInfo.json", CONTENT_TYPE_JSON);
+
+        // assume workspace name contains "default", might not
+        // always be the case as the default workspace is selected
+        // by the JCR implementation due to SLING-256
+        assertJavascript("admin.true", content, "out.println(data.userID + '.' + (data.workspace.indexOf('default') >= 0) )");
+    }
+
+    public void testNonexistentSlingUrl() throws IOException {
+        assertHttpStatus(HTTP_BASE_URL + "/sling.nothing", HttpServletResponse.SC_NOT_FOUND);
+    }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/ExtensionServletTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/ExtensionServletTest.java
new file mode 100644
index 0000000..66ca149
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/ExtensionServletTest.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.launchpad.webapp.integrationtest.servlets.resolution;
+
+/** Test the ExtensionServlet */
+public class ExtensionServletTest extends ResolutionTestBase {
+  
+  public void testExtensionOne() throws Exception {
+    assertServlet(
+        getContent(testNodeNORT.nodeUrl + ".TEST_EXT_1", CONTENT_TYPE_PLAIN),
+        EXT_SERVLET_SUFFIX);
+  }
+  
+  public void testExtensionTwo() throws Exception {
+    assertServlet(
+        getContent(testNodeNORT.nodeUrl + ".TEST_EXT_2", CONTENT_TYPE_PLAIN), 
+        EXT_SERVLET_SUFFIX);
+  }
+  
+  public void testExtensionOther() throws Exception {
+    assertNotTestServlet(
+        getContent(testNodeNORT.nodeUrl + ".txt", CONTENT_TYPE_PLAIN));
+  }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/PrefixTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/PrefixTest.java
new file mode 100644
index 0000000..0d60e1d
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/PrefixTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.resolution;
+
+/** Verify that PrefixServletZero overrides PrefixServletMinusOne */
+public class PrefixTest extends ResolutionTestBase {
+  
+  public void testPrefixServletZeroPresent() throws Exception {
+    assertServlet(
+        getContent(testNodeNORT.nodeUrl + ".TEST_EXT_5", CONTENT_TYPE_PLAIN),
+        PREFIX_0_SERVLET_SUFFIX);
+  }
+  
+  public void testPrefixServletMinusOnePresent() throws Exception {
+    assertServlet(
+        getContent(testNodeNORT.nodeUrl + ".TEST_EXT_4", CONTENT_TYPE_PLAIN),
+        PREFIX_M1_SERVLET_SUFFIX);
+  }
+  
+  public void testPrefixServletZeroWins() throws Exception {
+    assertServlet(
+        getContent(testNodeNORT.nodeUrl + ".TEST_EXT_3", CONTENT_TYPE_PLAIN),
+        PREFIX_0_SERVLET_SUFFIX);
+  }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/PrioritiesTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/PrioritiesTest.java
new file mode 100644
index 0000000..1797a71
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/PrioritiesTest.java
@@ -0,0 +1,27 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.resolution;
+
+/** Test the priority of servlet selection mechanisms */
+public class PrioritiesTest extends ResolutionTestBase {
+  
+  public void testExtensionWinsOverSelector() throws Exception {
+    assertServlet(
+        getContent(testNodeNORT.nodeUrl + ".TEST_SEL_2.TEST_EXT_1", CONTENT_TYPE_PLAIN),
+        EXT_SERVLET_SUFFIX);
+  }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/PutMethodServletTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/PutMethodServletTest.java
new file mode 100644
index 0000000..9c98f40
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/PutMethodServletTest.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.launchpad.webapp.integrationtest.servlets.resolution;
+
+import org.apache.commons.httpclient.methods.PutMethod;
+
+/** Test the PutMethodServlet resolution */
+public class PutMethodServletTest extends ResolutionTestBase {
+  
+  public void testPutMethodServletSpecificRT() throws Exception {
+    final PutMethod put = new PutMethod(testNodeRT.nodeUrl);
+    final int status = httpClient.executeMethod(put);
+    assertEquals("PUT to testNodeRT should return 200", 200, status);
+    final String content = put.getResponseBodyAsString();
+    assertServlet(content, PUT_SERVLET_SUFFIX);
+  }
+  
+  public void testPutMethodServletDefaultRT() throws Exception {
+    final PutMethod put = new PutMethod(testNodeNORT.nodeUrl);
+    final int status = httpClient.executeMethod(put);
+    assertFalse("PUT to testNodeRT should not return 200", 200 == status);
+  }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/ResolutionTestBase.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/ResolutionTestBase.java
new file mode 100644
index 0000000..426f28e
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/ResolutionTestBase.java
@@ -0,0 +1,87 @@
+/*
+ * 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.launchpad.webapp.integrationtest.servlets.resolution;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/** Base class for servlet resolution tests */
+class ResolutionTestBase extends HttpTestBase {
+  public static final String CLASS_PROP = "servlet.class.name";
+  public static final String TEST_SERVLET_MARKER = "created by org.apache.sling.launchpad.testservices.servlets";
+  public static final String TEST_RESOURCE_TYPE = "LAUNCHPAD_TEST_ResourceType";
+  public static final String TEST_PATH = "/servlet-resolution-tests/" + System.currentTimeMillis();
+   
+  public static final String EXT_SERVLET_SUFFIX = "testservices.servlets.ExtensionServlet";
+  public static final String SEL_SERVLET_SUFFIX = "testservices.servlets.SelectorServlet";
+  public static final String PREFIX_0_SERVLET_SUFFIX = "testservices.servlets.PrefixServletZero";
+  public static final String PREFIX_M1_SERVLET_SUFFIX = "testservices.servlets.PrefixServletMinusOne";
+  public static final String PUT_SERVLET_SUFFIX = "testservices.servlets.PutMethodServlet";
+  
+  protected TestNode testNodeNORT;
+  protected TestNode testNodeRT;
+  
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    testNodeNORT = new TestNode(HTTP_BASE_URL + TEST_PATH, null);
+    final Map<String, String> properties = new HashMap<String, String>();
+    properties.put("sling:resourceType", TEST_RESOURCE_TYPE);
+    testNodeRT = new TestNode(HTTP_BASE_URL + TEST_PATH, properties);
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    super.tearDown();
+    testNodeNORT.delete();
+    testNodeRT.delete();
+  }
+
+  /** Asserts that the given content is in Properties format and
+   *  contains a property named CLASS_PROP that ends with
+   *  expected suffix  
+   */
+  protected void assertServlet(String content, String expectedSuffix) throws IOException {
+    final Properties props = new Properties();
+    final InputStream is = new ByteArrayInputStream(content.getBytes());
+    props.load(is);
+    assertTrue(
+        "Content represents a non-empty Properties object (" + content + ")",
+        props.size() > 0);
+    final String clazz = props.getProperty(CLASS_PROP);
+    assertNotNull(
+        "Content contains " + CLASS_PROP + " property (" + content + ")",
+        clazz);
+    assertTrue(
+        CLASS_PROP + " property value (" + clazz + ") ends with " + expectedSuffix,
+        clazz.endsWith(expectedSuffix));
+  }
+  
+  /** Assert that content does not contain TEST_SERVLET_MARKER
+   */
+  protected void assertNotTestServlet(String content) {
+    if(content.contains(TEST_SERVLET_MARKER)) {
+      fail("Content should not contain " + TEST_SERVLET_MARKER + " marker (" + content + ")");
+    }
+  }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/SelectorServletTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/SelectorServletTest.java
new file mode 100644
index 0000000..04d392e
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/servlets/resolution/SelectorServletTest.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.launchpad.webapp.integrationtest.servlets.resolution;
+
+/** Test the SelectorServlet */
+public class SelectorServletTest extends ResolutionTestBase {
+  
+  public void testSelectorOne() throws Exception {
+    assertServlet(
+        getContent(testNodeNORT.nodeUrl + ".TEST_SEL_1.txt", CONTENT_TYPE_PLAIN),
+        SEL_SERVLET_SUFFIX);
+  }
+  
+  public void testSelectorTwo() throws Exception {
+    assertServlet(
+        getContent(testNodeNORT.nodeUrl + ".TEST_SEL_2.txt", CONTENT_TYPE_PLAIN),
+        SEL_SERVLET_SUFFIX);
+  }
+  
+  public void testSelectorOther() throws Exception {
+    assertNotTestServlet(
+        getContent(testNodeNORT.nodeUrl + ".TEST_SEL_3.txt", CONTENT_TYPE_PLAIN));
+  }
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/AbstractUserManagerTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/AbstractUserManagerTest.java
new file mode 100644
index 0000000..0dd0ce5
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/AbstractUserManagerTest.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The 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.launchpad.webapp.integrationtest.userManager;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthScope;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+
+/**
+ * Base class for UserManager tests.
+ */
+public abstract class AbstractUserManagerTest extends HttpTestBase {
+	
+    /** Execute a POST request and check status */
+    protected void assertAuthenticatedAdminPostStatus(String url, int expectedStatusCode, List<NameValuePair> postParams, String assertMessage)
+    throws IOException {
+        Credentials defaultcreds = new UsernamePasswordCredentials("admin", "admin");
+        assertAuthenticatedPostStatus(defaultcreds, url, expectedStatusCode, postParams, assertMessage);
+    }
+
+    /** Execute a POST request and check status */
+    protected void assertAuthenticatedPostStatus(Credentials creds, String url, int expectedStatusCode, List<NameValuePair> postParams, String assertMessage)
+    throws IOException {
+        final PostMethod post = new PostMethod(url);
+        post.setFollowRedirects(false);
+        
+        URL baseUrl = new URL(HTTP_BASE_URL);
+        AuthScope authScope = new AuthScope(baseUrl.getHost(), baseUrl.getPort(), AuthScope.ANY_REALM);
+        post.setDoAuthentication(true);
+        Credentials oldCredentials = httpClient.getState().getCredentials(authScope);
+        try {
+			httpClient.getState().setCredentials(authScope, creds);
+	        
+	        if(postParams!=null) {
+	            final NameValuePair [] nvp = {};
+	            post.setRequestBody(postParams.toArray(nvp));
+	        }
+	
+	        final int status = httpClient.executeMethod(post);
+	        if(assertMessage == null) {
+	            assertEquals(expectedStatusCode, status);
+	        } else {
+	            assertEquals(assertMessage, expectedStatusCode, status);
+	        }
+        } finally {
+        	httpClient.getState().setCredentials(authScope, oldCredentials);
+        }
+    }
+
+    /** Verify that given URL returns expectedStatusCode
+     * @throws IOException */
+    protected void assertAuthenticatedHttpStatus(Credentials creds, String urlString, int expectedStatusCode, String assertMessage) throws IOException {
+        URL baseUrl = new URL(HTTP_BASE_URL);
+        AuthScope authScope = new AuthScope(baseUrl.getHost(), baseUrl.getPort(), AuthScope.ANY_REALM);
+        GetMethod getMethod = new GetMethod(urlString);
+        getMethod.setDoAuthentication(true);
+        Credentials oldCredentials = httpClient.getState().getCredentials(authScope);
+    	try {
+			httpClient.getState().setCredentials(authScope, creds);
+
+			final int status = httpClient.executeMethod(getMethod);
+            if(assertMessage == null) {
+                assertEquals(urlString,expectedStatusCode, status);
+            } else {
+                assertEquals(assertMessage, expectedStatusCode, status);
+            }
+    	} finally {
+        	httpClient.getState().setCredentials(authScope, oldCredentials);
+    	}
+    }
+
+    
+    /** retrieve the contents of given URL and assert its content type
+     * @param expectedContentType use CONTENT_TYPE_DONTCARE if must not be checked 
+     * @throws IOException
+     * @throws HttpException */
+    protected String getAuthenticatedContent(Credentials creds, String url, String expectedContentType, List<NameValuePair> params, int expectedStatusCode) throws IOException {
+        final GetMethod get = new GetMethod(url);
+
+        URL baseUrl = new URL(HTTP_BASE_URL);
+        AuthScope authScope = new AuthScope(baseUrl.getHost(), baseUrl.getPort(), AuthScope.ANY_REALM);
+        get.setDoAuthentication(true);
+        Credentials oldCredentials = httpClient.getState().getCredentials(authScope);
+    	try {
+			httpClient.getState().setCredentials(authScope, creds);
+			
+	        if(params != null) {
+	            final NameValuePair [] nvp = new NameValuePair[0];
+	            get.setQueryString(params.toArray(nvp));
+	        }
+	        final int status = httpClient.executeMethod(get);
+	        final InputStream is = get.getResponseBodyAsStream();
+	        final StringBuffer content = new StringBuffer();
+	        final String charset = get.getResponseCharSet();
+	        final byte [] buffer = new byte[16384];
+	        int n = 0;
+	        while( (n = is.read(buffer, 0, buffer.length)) > 0) {
+	            content.append(new String(buffer, 0, n, charset));
+	        }
+	        assertEquals("Expected status " + expectedStatusCode + " for " + url + " (content=" + content + ")",
+	                expectedStatusCode,status);
+	        final Header h = get.getResponseHeader("Content-Type");
+	        if(expectedContentType == null) {
+	            if(h!=null) {
+	                fail("Expected null Content-Type, got " + h.getValue());
+	            }
+	        } else if(CONTENT_TYPE_DONTCARE.equals(expectedContentType)) {
+	            // no check
+	        } else if(h==null) {
+	            fail(
+	                    "Expected Content-Type that starts with '" + expectedContentType
+	                    +" but got no Content-Type header at " + url
+	            );
+	        } else {
+	            assertTrue(
+	                "Expected Content-Type that starts with '" + expectedContentType
+	                + "' for " + url + ", got '" + h.getValue() + "'",
+	                h.getValue().startsWith(expectedContentType)
+	            );
+	        }
+	        return content.toString();
+			
+    	} finally {
+        	httpClient.getState().setCredentials(authScope, oldCredentials);
+    	}
+    }
+    
+    
+    protected static int counter = 1;
+    
+	protected String createTestUser() throws IOException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user.create.html";
+
+		String testUserId = "testUser" + (counter++);
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":name", testUserId));
+		postParams.add(new NameValuePair("pwd", "testPwd"));
+		postParams.add(new NameValuePair("pwdConfirm", "testPwd"));
+		assertPostStatus(postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		return testUserId;
+	}
+    
+	protected String createTestGroup() throws IOException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/group.create.html";
+
+		String testGroupId = "testGroup" + (counter++);
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":name", testGroupId));
+		
+		//success would be a redirect to the welcome page of the webapp
+		assertAuthenticatedAdminPostStatus(postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		return testGroupId;
+	}
+	
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/CreateGroupTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/CreateGroupTest.java
new file mode 100644
index 0000000..3075211
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/CreateGroupTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.launchpad.webapp.integrationtest.userManager;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+
+/**
+ * Tests for the 'createGroup' Sling Post Operation
+ */
+public class CreateGroupTest extends AbstractUserManagerTest {
+
+	String testGroupId = null;
+	
+	@Override
+	protected void tearDown() throws Exception {
+		if (testGroupId != null) {
+			//remove the test group if it exists.
+			String postUrl = HTTP_BASE_URL + "/system/userManager/group/" + testGroupId + ".delete.html";
+			List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+			assertAuthenticatedAdminPostStatus(postUrl, HttpServletResponse.SC_OK, postParams, null);
+		}
+
+		super.tearDown();
+	}
+
+	public void testCreateGroup() throws IOException, JSONException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/group.create.html";
+
+		testGroupId = "testGroup" + (counter++);
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":name", testGroupId));
+		assertAuthenticatedAdminPostStatus(postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		//fetch the group profile json to verify the settings
+		String getUrl = HTTP_BASE_URL + "/system/userManager/group/" + testGroupId + ".json";
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		String json = getAuthenticatedContent(creds, getUrl, CONTENT_TYPE_JSON, null, HttpServletResponse.SC_OK);
+		assertNotNull(json);
+		JSONObject jsonObj = new JSONObject(json);
+		assertEquals(testGroupId, jsonObj.getString("rep:principalName"));
+	}
+
+	public void testCreateGroupMissingGroupId() throws IOException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/group.create.html";
+
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		assertAuthenticatedAdminPostStatus(postUrl, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, postParams, null);
+	}
+
+	public void testCreateGroupAlreadyExists() throws IOException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/group.create.html";
+
+		testGroupId = "testGroup" + (counter++);
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":name", testGroupId));
+		assertAuthenticatedAdminPostStatus(postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		//post the same info again, should fail
+		assertAuthenticatedAdminPostStatus(postUrl, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, postParams, null);
+	}
+	
+	public void testCreateGroupWithExtraProperties() throws IOException, JSONException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/group.create.html";
+
+		testGroupId = "testGroup" + (counter++);
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":name", testGroupId));
+		postParams.add(new NameValuePair("displayName", "My Test Group"));
+		postParams.add(new NameValuePair("url", "http://www.apache.org"));
+		assertAuthenticatedAdminPostStatus(postUrl, HttpServletResponse.SC_OK, postParams, null);
+
+		//fetch the group profile json to verify the settings
+		String getUrl = HTTP_BASE_URL + "/system/userManager/group/" + testGroupId + ".json";
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		String json = getAuthenticatedContent(creds, getUrl, CONTENT_TYPE_JSON, null, HttpServletResponse.SC_OK);
+		assertNotNull(json);
+		JSONObject jsonObj = new JSONObject(json);
+		assertEquals(testGroupId, jsonObj.getString("rep:principalName"));
+		assertEquals("My Test Group", jsonObj.getString("displayName"));
+		assertEquals("http://www.apache.org", jsonObj.getString("url"));
+	}		
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/CreateUserTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/CreateUserTest.java
new file mode 100644
index 0000000..2fcdc93
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/CreateUserTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.launchpad.webapp.integrationtest.userManager;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+
+/**
+ * Tests for the 'createUser' Sling Post Operation
+ */
+public class CreateUserTest extends AbstractUserManagerTest {
+
+	String testUserId = null;
+	
+	@Override
+	protected void tearDown() throws Exception {
+		if (testUserId != null) {
+			//remove the test user if it exists.
+			String postUrl = HTTP_BASE_URL + "/system/userManager/user/" + testUserId + ".delete.html";
+			List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+			assertAuthenticatedAdminPostStatus(postUrl, HttpServletResponse.SC_OK, postParams, null);
+		}
+		super.tearDown();
+	}
+
+	/*
+		<form action="/system/userManager/user.create.html" method="POST">
+		   <div>Name: <input type="text" name=":name" value="testUser" /></div>
+		   <div>Password: <input type="text" name="pwd" value="testUser" /></div>
+		   <div>Password Confirm: <input type="text" name="pwdConfirm" value="testUser" /></div>
+		   <input type="submit" value="Submit" />
+		</form>
+	 */
+	public void testCreateUser() throws IOException, JSONException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user.create.html";
+        
+		testUserId = "testUser" + (counter++);
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":name", testUserId));
+		postParams.add(new NameValuePair("pwd", "testPwd"));
+		postParams.add(new NameValuePair("pwdConfirm", "testPwd"));
+		assertPostStatus(postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		//fetch the user profile json to verify the settings
+		String getUrl = HTTP_BASE_URL + "/system/userManager/user/" + testUserId + ".json";
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		String json = getAuthenticatedContent(creds, getUrl, CONTENT_TYPE_JSON, null, HttpServletResponse.SC_OK);
+		assertNotNull(json);
+		JSONObject jsonObj = new JSONObject(json);
+		assertEquals(testUserId, jsonObj.getString("rep:principalName"));
+		assertFalse(jsonObj.has(":name"));
+		assertFalse(jsonObj.has("pwd"));
+		assertFalse(jsonObj.has("pwdConfirm"));
+	}
+
+	public void testCreateUserMissingUserId() throws IOException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user.create.html";
+
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		assertPostStatus(postUrl, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, postParams, null);
+	}
+
+	public void testCreateUserMissingPwd() throws IOException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user.create.html";
+
+        String userId = "testUser" + (counter++);
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":name", userId));
+		assertPostStatus(postUrl, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, postParams, null);
+	}
+
+	public void testCreateUserWrongConfirmPwd() throws IOException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user.create.html";
+
+        String userId = "testUser" + (counter++);
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":name", userId));
+		postParams.add(new NameValuePair("pwd", "testPwd"));
+		postParams.add(new NameValuePair("pwdConfirm", "testPwd2"));
+		assertPostStatus(postUrl, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, postParams, null);
+	}
+
+	public void testCreateUserUserAlreadyExists() throws IOException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user.create.html";
+
+		testUserId = "testUser" + (counter++);
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":name", testUserId));
+		postParams.add(new NameValuePair("pwd", "testPwd"));
+		postParams.add(new NameValuePair("pwdConfirm", "testPwd"));
+		assertPostStatus(postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		//post the same info again, should fail
+		assertPostStatus(postUrl, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, postParams, null);
+	}
+	
+	/*
+	<form action="/system/userManager/user.create.html" method="POST">
+	   <div>Name: <input type="text" name=":name" value="testUser" /></div>
+	   <div>Password: <input type="text" name="pwd" value="testUser" /></div>
+	   <div>Password Confirm: <input type="text" name="pwdConfirm" value="testUser" /></div>
+	   <div>Extra Property #1: <input type="text" name="displayName" value="My Test User" /></div>
+	   <div>Extra Property #2: <input type="text" name="url" value="http://www.apache.org" /></div>
+	   <input type="submit" value="Submit" />
+	</form>
+	*/
+	public void testCreateUserWithExtraProperties() throws IOException, JSONException {
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user.create.html";
+
+		testUserId = "testUser" + (counter++);
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":name", testUserId));
+		postParams.add(new NameValuePair("pwd", "testPwd"));
+		postParams.add(new NameValuePair("pwdConfirm", "testPwd"));
+		postParams.add(new NameValuePair("displayName", "My Test User"));
+		postParams.add(new NameValuePair("url", "http://www.apache.org"));
+		assertPostStatus(postUrl, HttpServletResponse.SC_OK, postParams, null);
+
+		//fetch the user profile json to verify the settings
+		String getUrl = HTTP_BASE_URL + "/system/userManager/user/" + testUserId + ".json";
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		String json = getAuthenticatedContent(creds, getUrl, CONTENT_TYPE_JSON, null, HttpServletResponse.SC_OK);
+		assertNotNull(json);
+		JSONObject jsonObj = new JSONObject(json);
+		assertEquals(testUserId, jsonObj.getString("rep:principalName"));
+		assertEquals("My Test User", jsonObj.getString("displayName"));
+		assertEquals("http://www.apache.org", jsonObj.getString("url"));
+		assertFalse(jsonObj.has(":name"));
+		assertFalse(jsonObj.has("pwd"));
+		assertFalse(jsonObj.has("pwdConfirm"));
+	}		
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/RemoveAuthorizablesTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/RemoveAuthorizablesTest.java
new file mode 100644
index 0000000..35b7172
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/RemoveAuthorizablesTest.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.launchpad.webapp.integrationtest.userManager;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+
+/**
+ * Tests for the 'removeAuthorizable' Sling Post Operation
+ */
+public class RemoveAuthorizablesTest extends AbstractUserManagerTest {
+
+	public void testRemoveUser() throws IOException {
+		String userId = createTestUser();
+		
+        Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+
+		String getUrl = HTTP_BASE_URL + "/system/userManager/user/" + userId + ".json";
+		assertAuthenticatedHttpStatus(creds, getUrl, HttpServletResponse.SC_OK, null); //make sure the profile request returns some data
+
+		String postUrl = HTTP_BASE_URL + "/system/userManager/user/" + userId + ".delete.html";
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		getUrl = HTTP_BASE_URL + "/system/userManager/user/" + userId + ".json";
+		assertAuthenticatedHttpStatus(creds, getUrl, HttpServletResponse.SC_NOT_FOUND, null); //make sure the profile request returns some data
+	}
+	
+	public void testRemoveGroup() throws IOException {
+		String groupId = createTestGroup();
+		
+        Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+
+		String getUrl = HTTP_BASE_URL + "/system/userManager/group/" + groupId + ".json";
+		assertAuthenticatedHttpStatus(creds, getUrl, HttpServletResponse.SC_OK, null); //make sure the profile request returns some data
+
+		String postUrl = HTTP_BASE_URL + "/system/userManager/group/" + groupId + ".delete.html";
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		getUrl = HTTP_BASE_URL + "/system/userManager/group/" + groupId + ".json";
+		assertAuthenticatedHttpStatus(creds, getUrl, HttpServletResponse.SC_NOT_FOUND, null); //make sure the profile request returns some data
+	}
+
+	public void testRemoveAuthorizables() throws IOException {
+		String userId = createTestUser();
+		String groupId = createTestGroup();
+		
+        Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+
+		String getUrl = HTTP_BASE_URL + "/system/userManager/user/" + userId + ".json";
+		assertAuthenticatedHttpStatus(creds, getUrl, HttpServletResponse.SC_OK, null); //make sure the profile request returns some data
+
+		getUrl = HTTP_BASE_URL + "/system/userManager/group/" + groupId + ".json";
+		assertAuthenticatedHttpStatus(creds, getUrl, HttpServletResponse.SC_OK, null); //make sure the profile request returns some data
+		
+		String postUrl = HTTP_BASE_URL + "/system/userManager.delete.html";
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":applyTo", "group/" + groupId));
+		postParams.add(new NameValuePair(":applyTo", "user/" + userId));
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		getUrl = HTTP_BASE_URL + "/system/userManager/user/" + userId + ".json";
+		assertAuthenticatedHttpStatus(creds, getUrl, HttpServletResponse.SC_NOT_FOUND, null); //make sure the profile request returns some data
+
+		getUrl = HTTP_BASE_URL + "/system/userManager/group/" + groupId + ".json";
+		assertAuthenticatedHttpStatus(creds, getUrl, HttpServletResponse.SC_NOT_FOUND, null); //make sure the profile request returns some data
+	}
+}
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/UpdateGroupTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/UpdateGroupTest.java
new file mode 100644
index 0000000..41f9d71
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/UpdateGroupTest.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.launchpad.webapp.integrationtest.userManager;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+
+/**
+ * Tests for the 'updateAuthorizable' Sling Post Operation on
+ * a group resource.
+ */
+public class UpdateGroupTest extends AbstractUserManagerTest {
+
+	String testGroupId = null;
+	
+	@Override
+	protected void tearDown() throws Exception {
+		if (testGroupId != null) {
+			//remove the test user if it exists.
+			String postUrl = HTTP_BASE_URL + "/system/userManager/group/" + testGroupId + ".delete.html";
+			List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+			assertAuthenticatedAdminPostStatus(postUrl, HttpServletResponse.SC_OK, postParams, null);
+		}
+
+		super.tearDown();
+	}
+
+	public void testUpdateGroup() throws IOException, JSONException {
+		testGroupId = createTestGroup();
+		
+        String postUrl = HTTP_BASE_URL + "/system/userManager/group/" + testGroupId + ".update.html";
+
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair("displayName", "My Updated Test Group"));
+		postParams.add(new NameValuePair("url", "http://www.apache.org/updated"));
+		
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		//fetch the user profile json to verify the settings
+		String getUrl = HTTP_BASE_URL + "/system/userManager/group/" + testGroupId + ".json";
+		assertAuthenticatedHttpStatus(creds, getUrl, HttpServletResponse.SC_OK, null); //make sure the profile request returns some data
+		String json = getAuthenticatedContent(creds, getUrl, CONTENT_TYPE_JSON, null, HttpServletResponse.SC_OK);
+		assertNotNull(json);
+		JSONObject jsonObj = new JSONObject(json);
+		assertEquals("My Updated Test Group", jsonObj.getString("displayName"));
+		assertEquals("http://www.apache.org/updated", jsonObj.getString("url"));
+	}
+	
+	public void testUpdateGroupMembers() throws IOException, JSONException {
+		testGroupId = createTestGroup();
+		
+        String postUrl = HTTP_BASE_URL + "/system/userManager/group/" + testGroupId + ".update.html";
+
+        //TODO: verify this works....
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair(":member", "../user/testUser"));
+		postParams.add(new NameValuePair(":member@Delete", "testGroup"));
+		
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+        //TODO: verify the group membership is correct....
+	}
+	
+}
+
diff --git a/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/UpdateUserTest.java b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/UpdateUserTest.java
new file mode 100644
index 0000000..cd40386
--- /dev/null
+++ b/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/UpdateUserTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.launchpad.webapp.integrationtest.userManager;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+
+/**
+ * Tests for the 'updateAuthorizable' and 'changePassword' Sling Post 
+ * Operations on a user resource.
+ */
+public class UpdateUserTest extends AbstractUserManagerTest {
+
+	String testUserId = null;
+	
+	@Override
+	protected void tearDown() throws Exception {
+		if (testUserId != null) {
+			//remove the test user if it exists.
+			String postUrl = HTTP_BASE_URL + "/system/userManager/user/" + testUserId + ".delete.html";
+			List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+			assertAuthenticatedAdminPostStatus(postUrl, HttpServletResponse.SC_OK, postParams, null);
+		}
+
+		super.tearDown();
+	}
+
+	public void testUpdateUser() throws IOException, JSONException {
+		testUserId = createTestUser();
+		
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user/" + testUserId + ".update.html";
+
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair("displayName", "My Updated Test User"));
+		postParams.add(new NameValuePair("url", "http://www.apache.org/updated"));
+		Credentials creds = new UsernamePasswordCredentials(testUserId, "testPwd");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+		
+		//fetch the user profile json to verify the settings
+		String getUrl = HTTP_BASE_URL + "/system/userManager/user/" + testUserId + ".json";
+		assertAuthenticatedHttpStatus(creds, getUrl, HttpServletResponse.SC_OK, null); //make sure the profile request returns some data
+		String json = getAuthenticatedContent(creds, getUrl, CONTENT_TYPE_JSON, null, HttpServletResponse.SC_OK);
+		assertNotNull(json);
+		JSONObject jsonObj = new JSONObject(json);
+		assertEquals("My Updated Test User", jsonObj.getString("displayName"));
+		assertEquals("http://www.apache.org/updated", jsonObj.getString("url"));
+	}
+	
+	public void testChangeUserPassword() throws IOException {
+		testUserId = createTestUser();
+		
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user/" + testUserId + ".changePassword.html";
+
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair("oldPwd", "testPwd"));
+		postParams.add(new NameValuePair("newPwd", "testNewPwd"));
+		postParams.add(new NameValuePair("newPwdConfirm", "testNewPwd"));
+
+		Credentials creds = new UsernamePasswordCredentials(testUserId, "testPwd");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+	}
+	
+	public void testChangeUserPasswordWrongOldPwd() throws IOException {
+		testUserId = createTestUser();
+		
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user/" + testUserId + ".changePassword.html";
+
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair("oldPwd", "wrongTestPwd"));
+		postParams.add(new NameValuePair("newPwd", "testNewPwd"));
+		postParams.add(new NameValuePair("newPwdConfirm", "testNewPwd"));
+		
+		//Credentials creds = new UsernamePasswordCredentials(testUserId, "testPwd");
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, postParams, null);
+	}
+
+	public void testChangeUserPasswordWrongConfirmPwd() throws IOException {
+		testUserId = createTestUser();
+		
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user/" + testUserId + ".changePassword.html";
+
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair("oldPwd", "testPwd"));
+		postParams.add(new NameValuePair("newPwd", "testNewPwd"));
+		postParams.add(new NameValuePair("newPwdConfirm", "wrongTestNewPwd"));
+		
+		//Credentials creds = new UsernamePasswordCredentials(testUserId, "testPwd");
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, postParams, null);
+	}
+	
+}
diff --git a/src/test/resources/integration-test/builtin-objects.esp b/src/test/resources/integration-test/builtin-objects.esp
new file mode 100644
index 0000000..a14cd05
--- /dev/null
+++ b/src/test/resources/integration-test/builtin-objects.esp
@@ -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.
+ */
+ 
+<%-- used by ScriptBuiltinObjectsTest --%>
+<html>
+	<body>
+		<h1>ESP template</h1>
+		<p>currentNode.text:<%= currentNode.text %></p>
+	</body>
+	
+	<!-- 
+		TODO we should test access to a well-known service
+		via the ServiceLocator - for now just check that it's
+		available 
+	-->
+	<%
+		var sc = sling.getService(Packages.java.lang.String);
+	%>
+	<p>sc:<%= sc %></p>
+	
+	<!-- test access to Response -->
+	<p>SlingHttpServletResponse:<%= response.containsHeader('NOT_A_HEADER') %></p>
+	
+	<!-- sling object is tested elsewhere (IncludeTest) -->
+	
+</html>
diff --git a/src/test/resources/integration-test/dump-resource.ecma b/src/test/resources/integration-test/dump-resource.ecma
new file mode 100644
index 0000000..9000dd2
--- /dev/null
+++ b/src/test/resources/integration-test/dump-resource.ecma
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+ 
+// recursive dump of a Resource in server-side javascript
+
+function dumpResource(r, level) {
+	out.print(level + " " + r + '\n');
+	
+	var iterator = r.resourceResolver.listChildren(r);
+	while(iterator.hasNext()) {
+		dumpResource(iterator.next(), level + 1);
+	}
+}
+
+dumpResource(resource, 1);
diff --git a/src/test/resources/integration-test/esp-load/included-a.esp b/src/test/resources/integration-test/esp-load/included-a.esp
new file mode 100644
index 0000000..56f05f9
--- /dev/null
+++ b/src/test/resources/integration-test/esp-load/included-a.esp
@@ -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.
+ */
+
+// Test SLING-428
+included-a.esp before load.
+
+<% load("subfolder/included-b.esp"); %>
+
+included-a.esp after load
+
+<%
+// esp is templating, so one needs to enclose functions
+// in the appropriate markers
+function functionFromIncludedA() {
+  %>Here's more from included-a<%
+}
+%>
\ No newline at end of file
diff --git a/src/test/resources/integration-test/esp-load/main.esp b/src/test/resources/integration-test/esp-load/main.esp
new file mode 100644
index 0000000..5bd09b9
--- /dev/null
+++ b/src/test/resources/integration-test/esp-load/main.esp
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+// Test SLING-428
+main.esp before load.
+
+<% load(currentNode.scriptToInclude); %>
+
+main.esp after load
+
+<% functionFromIncludedA() %>
\ No newline at end of file
diff --git a/src/test/resources/integration-test/esp-load/subfolder/included-b.esp b/src/test/resources/integration-test/esp-load/subfolder/included-b.esp
new file mode 100644
index 0000000..a1342f4
--- /dev/null
+++ b/src/test/resources/integration-test/esp-load/subfolder/included-b.esp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+// Test SLING-428
+included-b.esp
\ No newline at end of file
diff --git a/src/test/resources/integration-test/file-to-upload.txt b/src/test/resources/integration-test/file-to-upload.txt
new file mode 100644
index 0000000..367f23d
--- /dev/null
+++ b/src/test/resources/integration-test/file-to-upload.txt
@@ -0,0 +1,12 @@
+This file is used by UploadFileTest.java.
+
+In must contain http://www.apache.org/licenses/LICENSE-2.0 for tests.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Fusce semper ipsum et lorem. In hac habitasse 
+platea dictumst. Donec dictum tincidunt purus. Aenean quis nunc. Aliquam rhoncus. Proin sed risus. 
+Maecenas porta arcu in nisi. Pellentesque quis sapien quis lectus vehicula aliquet. Cras ornare elit 
+eget massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed 
+ut justo. Integer porttitor quam. Aliquam aliquet. Nulla interdum arcu vitae nibh. Morbi dapibus odio 
+a sem. Integer dictum. Praesent vel eros nec ipsum venenatis malesuada. Vestibulum rutrum mi ac ligula. 
+Ut nisl ligula, vehicula dignissim, accumsan quis, faucibus sed, sapien. Quisque purus tellus, euismod 
+id, auctor quis, rutrum non, augue.
\ No newline at end of file
diff --git a/src/test/resources/integration-test/forward-forced.esp b/src/test/resources/integration-test/forward-forced.esp
new file mode 100644
index 0000000..90670f5
--- /dev/null
+++ b/src/test/resources/integration-test/forward-forced.esp
@@ -0,0 +1,31 @@
+<%
+
+/*
+ * 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.
+ */
+ 
+// used by ForwardTest
+%><html>
+	<body>
+		<h1>ESP template</h1>
+		<p class="main"><%= currentNode.text %></p>
+		<div>
+		  Forced resource type:<%= resource.resourceType %></p>. 
+		</div>
+	</body>
+</html>
\ No newline at end of file
diff --git a/src/test/resources/integration-test/forward-forced.jsp b/src/test/resources/integration-test/forward-forced.jsp
new file mode 100644
index 0000000..aa1d247
--- /dev/null
+++ b/src/test/resources/integration-test/forward-forced.jsp
@@ -0,0 +1,31 @@
+<%--
+/*
+ * 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.
+--%><%@page session="false"%><%
+%><%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%><%
+%><sling:defineObjects/><%
+// used by ForwardTest
+%><html>
+	<body>
+		<h1>JSP template</h1>
+		<p class="main"><%= currentNode.getProperty("text").getString() %></p>
+		<div>
+		  Forced resource type:<%= resource.getResourceType() %></p>. 
+		</div>
+	</body>
+</html>
\ No newline at end of file
diff --git a/src/test/resources/integration-test/forward-test.esp b/src/test/resources/integration-test/forward-test.esp
new file mode 100644
index 0000000..fcf29d6
--- /dev/null
+++ b/src/test/resources/integration-test/forward-test.esp
@@ -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.
+ */
+ 
+// used by ForwardTest
+
+// Test 3: Forced Resource Type
+if(currentNode.pathToInclude && currentNode.forceResourceType) {
+  sling.forward(currentNode.pathToInclude, currentNode.forceResourceType);
+}
+
+else
+
+// Test 1: Simple Forward 
+if(currentNode.pathToInclude) {
+  sling.forward(currentNode.pathToInclude);
+}
+
+else
+
+// Test 2: Infinite Loop
+if(currentNode.testInfiniteLoop) {
+  // try to include the item itself, to cause an infinite loop
+  sling.forward(resource.getPath());
+} else {
+
+// Test 0: No Forward
+%><html>
+	<body>
+		<h1>ESP template</h1>
+		<p class="main"><%= currentNode.text %></p>
+	</body>
+</html><%
+
+}
+%>
\ No newline at end of file
diff --git a/src/test/resources/integration-test/forward-test.jsp b/src/test/resources/integration-test/forward-test.jsp
new file mode 100644
index 0000000..012449b
--- /dev/null
+++ b/src/test/resources/integration-test/forward-test.jsp
@@ -0,0 +1,76 @@
+<%--
+/*
+ * 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.
+--%><%@page session="false"%><%
+%><%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%><%
+%><sling:defineObjects/><%
+
+// used by JspForwardTest
+%><%!
+
+private String getProperty(javax.jcr.Node node, String propertyName) {
+    try {
+        if (node.hasProperty(propertyName)) {
+            return node.getProperty(propertyName).getString();
+        }
+    } catch (Throwable t) {
+        // don't care
+    }
+    return null;
+}
+
+%><%
+
+String pathToInclude = getProperty(currentNode, "pathToInclude");
+String forceResourceType = getProperty(currentNode, "forceResourceType");
+String testInfiniteLoop = getProperty(currentNode, "testInfiniteLoop");
+
+// Test 3: Forced Resource Type
+if(pathToInclude != null && forceResourceType != null) {
+    %><sling:forward path="<%= pathToInclude %>" resourceType="<%= forceResourceType %>"/><%
+}
+
+else
+
+// Test 1: Simple Forward 
+if(pathToInclude != null) {
+    %><sling:forward path="<%= pathToInclude %>"/><%
+}
+
+else
+
+// Test 2: Infinite Loop
+if(testInfiniteLoop != null) {
+  // try to include the item itself, to cause an infinite loop
+    %><sling:forward path="<%= resource.getPath() %>"/><%
+}
+
+else
+
+{
+
+// Test 0: No Forward
+%><html>
+	<body>
+		<h1>JSP template</h1>
+		<p class="main"><%= currentNode.getProperty("text").getString() %></p>
+	</body>
+</html><%
+
+}
+%>
\ No newline at end of file
diff --git a/src/test/resources/integration-test/include-forced.esp b/src/test/resources/integration-test/include-forced.esp
new file mode 100644
index 0000000..a3deb82
--- /dev/null
+++ b/src/test/resources/integration-test/include-forced.esp
@@ -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.
+ */
+ 
+<%-- used by IncludeTest --%>
+<div>
+  Forced resource type:<%= currentNode.text %></p>. 
+</div>
\ No newline at end of file
diff --git a/src/test/resources/integration-test/include-forced.jsp b/src/test/resources/integration-test/include-forced.jsp
new file mode 100644
index 0000000..5e756d7
--- /dev/null
+++ b/src/test/resources/integration-test/include-forced.jsp
@@ -0,0 +1,26 @@
+<%--
+/*
+ * 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.
+ */
+--%><%@page session="false"%><%
+%><%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%><%
+%><sling:defineObjects/><%
+// used by ForwardTest
+%><div>
+	  Forced resource type:<%= resource.getResourceType() %></p>. 
+</div>
diff --git a/src/test/resources/integration-test/include-test.esp b/src/test/resources/integration-test/include-test.esp
new file mode 100644
index 0000000..15095b6
--- /dev/null
+++ b/src/test/resources/integration-test/include-test.esp
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+ 
+<%-- used by IncludeTest --%>
+<html>
+	<body>
+		<h1>ESP template</h1>
+		<p class="main"><%= currentNode.text %></p>
+		
+		<h2>Test 1</h2>
+		<%
+			if(currentNode.pathToInclude) {
+			  %>
+			  <p>pathToInclude = <%= currentNode.pathToInclude %></p>
+  		  	  <p>Including <%= currentNode.pathToInclude %></p>
+			  <%
+			  sling.include(currentNode.pathToInclude);
+			}
+		%>
+		
+		<h2>Test 2</h2>
+		<%
+			if(currentNode.testInfiniteLoop) {
+			  %>
+			  <p>testInfiniteLoop = <%= currentNode.testInfiniteLoop %></p>
+			  <%
+			  // try to include the item itself, to cause an infinite loop
+			  sling.include(resource.getPath());
+			}
+		%>
+		
+		<h2>Test 3</h2>
+		<%
+			if(currentNode.pathToInclude && currentNode.forceResourceType) {
+			  %>
+			  <p>pathToInclude = <%= currentNode.pathToInclude %></p>
+  		  	  <p>Including <%= currentNode.pathToInclude %></p>
+			  <%
+			  sling.include(currentNode.pathToInclude, currentNode.forceResourceType);
+			}
+		%>
+	</body>
+</html>
diff --git a/src/test/resources/integration-test/include-test.jsp b/src/test/resources/integration-test/include-test.jsp
new file mode 100644
index 0000000..75a3f2b
--- /dev/null
+++ b/src/test/resources/integration-test/include-test.jsp
@@ -0,0 +1,103 @@
+<%--
+/*
+ * 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.
+--%><%@page session="false"%><%
+%><%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%><%
+%><sling:defineObjects/><%
+ 
+// used by IncludeTest
+%><%!
+
+private String getProperty(javax.jcr.Node node, String propertyName) {
+    try {
+        if (node.hasProperty(propertyName)) {
+            return node.getProperty(propertyName).getString();
+        }
+    } catch (Throwable t) {
+        // don't care
+    }
+    return null;
+}
+
+%><%
+
+String text = getProperty(currentNode, "text");
+String pathToInclude = getProperty(currentNode, "pathToInclude");
+String forceResourceType = getProperty(currentNode, "forceResourceType");
+String testInfiniteLoop = getProperty(currentNode, "testInfiniteLoop");
+String testMaxCalls = getProperty(currentNode, "testMaxCalls");
+
+%><html>
+	<body>
+		<h1>JSP template</h1>
+		<p class="main"><%= text %></p>
+		
+		<h2>Test 1</h2>
+		<%
+			if(pathToInclude != null) {
+			  %>
+			  <p>pathToInclude = <%= pathToInclude %></p>
+  		  	  <p>Including <%= pathToInclude %></p>
+  		  	  <sling:include path="<%= pathToInclude %>"/>
+			  <%
+			}
+		%>
+		
+		<h2>Test 2</h2>
+		<%
+			if(testInfiniteLoop != null) {
+			  %>
+			  <p>testInfiniteLoop = <%= testInfiniteLoop %></p>
+			  <%
+			  // try to include the item itself, to cause an infinite loop
+			  %>
+  		  	  <sling:include path="<%= resource.getPath() %>"/>
+  		  	  <%
+			}
+		%>
+		
+		<h2>Test 3</h2>
+		<%
+			if(pathToInclude != null && forceResourceType != null) {
+			  %>
+			  <p>pathToInclude = <%= pathToInclude %></p>
+  		  	  <p>Including <%= pathToInclude %></p>
+  		  	  <sling:include path="<%= pathToInclude %>" resourceType="<%= forceResourceType %>"/>
+			  <%
+			}
+		%>
+		
+		<h2>Test 4</h2>
+		<%
+			if(pathToInclude != null && testMaxCalls != null) {
+				%>
+				<p>pathToInclude = <%= pathToInclude %></p>
+				<p>Including <%= pathToInclude %></p>
+				<%
+			    for (int i=0; i < 1200; i++) {
+			        %>
+			        <%= i %><br />
+			        <hr />
+					<sling:include path="<%= pathToInclude %>" />
+			        <hr />
+					<%
+			    }
+			}
+		%>
+	</body>
+</html>
diff --git a/src/test/resources/integration-test/issues/sling457/a-foo.html.jsp b/src/test/resources/integration-test/issues/sling457/a-foo.html.jsp
new file mode 100644
index 0000000..ef434b8
--- /dev/null
+++ b/src/test/resources/integration-test/issues/sling457/a-foo.html.jsp
@@ -0,0 +1,21 @@
+<!--
+/*
+ * 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.
+-->
+<%@page session="false"%>
+foo.html.jsp
\ No newline at end of file
diff --git a/src/test/resources/integration-test/issues/sling457/b-b.jsp b/src/test/resources/integration-test/issues/sling457/b-b.jsp
new file mode 100644
index 0000000..f1c4ac7
--- /dev/null
+++ b/src/test/resources/integration-test/issues/sling457/b-b.jsp
@@ -0,0 +1,27 @@
+<!--
+/*
+ * 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.
+-->
+<%@page session="false"%>
+<%@page import="org.apache.sling.api.SlingHttpServletRequest"%>
+<%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%>
+<%
+	SlingHttpServletRequest req = (SlingHttpServletRequest) request;
+	String resType = req.getResource().getResourceType();
+%>
+<sling:include path="./image.foo.html" resourceType="<%= resType %>" />
\ No newline at end of file
diff --git a/src/test/resources/integration-test/issues/sling760/throw-with-markup.esp b/src/test/resources/integration-test/issues/sling760/throw-with-markup.esp
new file mode 100644
index 0000000..f600bcf
--- /dev/null
+++ b/src/test/resources/integration-test/issues/sling760/throw-with-markup.esp
@@ -0,0 +1,5 @@
+<%
+// SLING-760: test an error message with characters that must
+// be escaped 
+throw("This string contains <characters/> that must be filtered & escaped");
+%>
\ No newline at end of file
diff --git a/src/test/resources/integration-test/no-code.esp b/src/test/resources/integration-test/no-code.esp
new file mode 100644
index 0000000..cb9db23
--- /dev/null
+++ b/src/test/resources/integration-test/no-code.esp
@@ -0,0 +1 @@
+There's no code in this script, just this constant string
\ No newline at end of file
diff --git a/src/test/resources/integration-test/post-test.esp b/src/test/resources/integration-test/post-test.esp
new file mode 100644
index 0000000..c7cffe9
--- /dev/null
+++ b/src/test/resources/integration-test/post-test.esp
@@ -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.
+ */
+ 
+<%
+var length = 0;
+if (request.getRequestParameter("file") != null) {
+    var file = null;
+    // store file
+    var reqPara = request.getRequestParameter("file");
+    var is = reqPara.getInputStream();
+    file = Packages.java.io.File.createTempFile("posttest", ".txt");
+    var fout = new Packages.java.io.FileOutputStream(file);
+    var c;
+    while ((c = is.read()) != -1) {
+        fout.write(c);
+    }
+    fout.close();
+
+    // read length
+    length = file.length();
+}
+%><%=  Packages.java.lang.String.valueOf(length) %>
\ No newline at end of file
diff --git a/src/test/resources/integration-test/print.esp b/src/test/resources/integration-test/print.esp
new file mode 100644
index 0000000..dc584ad
--- /dev/null
+++ b/src/test/resources/integration-test/print.esp
@@ -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.
+ */
+
+// Verify that the print() method compiles
+<% print("something from print.esp"); %>
+print.esp ends
\ No newline at end of file
diff --git a/src/test/resources/integration-test/rendering-test-2.esp b/src/test/resources/integration-test/rendering-test-2.esp
new file mode 100644
index 0000000..b469c20
--- /dev/null
+++ b/src/test/resources/integration-test/rendering-test-2.esp
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+ 
+<%-- used by ScriptedRenderingTest --%>
+<html>
+	<body>
+		Template #2 for ESP tests 
+		<p><b><%= currentNode.text %></b></p>
+	</body>
+</html>
diff --git a/src/test/resources/integration-test/rendering-test-3.esp b/src/test/resources/integration-test/rendering-test-3.esp
new file mode 100644
index 0000000..f96eebf
--- /dev/null
+++ b/src/test/resources/integration-test/rendering-test-3.esp
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+ 
+<%-- used by ScriptedRenderingTest --%>
+<html>
+	<body>
+		Template #3 for ESP tests 
+		<p><em><%= currentNode.text %></em></p>
+	</body>
+</html>
diff --git a/src/test/resources/integration-test/rendering-test.ecma b/src/test/resources/integration-test/rendering-test.ecma
new file mode 100644
index 0000000..3c989a3
--- /dev/null
+++ b/src/test/resources/integration-test/rendering-test.ecma
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+ 
+// Used by ScriptedRenderingTest
+out.println("<html><body>");
+out.println("Raw javascript template");
+out.println("<p><em>" + currentNode.text + "</em></p>");
+out.print("</body></html>");
diff --git a/src/test/resources/integration-test/rendering-test.esp b/src/test/resources/integration-test/rendering-test.esp
new file mode 100644
index 0000000..63ba195
--- /dev/null
+++ b/src/test/resources/integration-test/rendering-test.esp
@@ -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.
+ */
+ 
+<%-- used by ScriptedRenderingTest --%>
+<html>
+	<body>
+		ESP template
+		<p><%= currentNode.text %></p>
+	
+		<!-- test SLING-142, compact syntax -->
+		<div class="SLING-142" id="${'2' + '2'}"/>
+	
+		<!-- test access to microsling java classes -->
+		<%
+			var list = new Packages.java.util.LinkedList();
+			list.add("LinkedListTest");
+		%>
+		<p>Test<%= list.get(0) %></p>
+
+	</body>
+</html>
diff --git a/src/test/resources/integration-test/rendering-test.jsp b/src/test/resources/integration-test/rendering-test.jsp
new file mode 100644
index 0000000..0b92d29
--- /dev/null
+++ b/src/test/resources/integration-test/rendering-test.jsp
@@ -0,0 +1,31 @@
+<!--
+/*
+ * 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.
+-->
+<!-- simple JSP rendering test -->
+<%@page session="false"%>
+<%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%>
+<sling:defineObjects/>
+
+<h1>JSP rendering result</h1>
+<p>
+	text value using resource.adaptTo:<%= resource.adaptTo(javax.jcr.Node.class).getProperty("text").getValue().getString() %>
+</p>
+<p>
+	text value using currentNode:<%= currentNode.getProperty("text").getValue().getString() %>
+</p>
diff --git a/src/test/resources/integration-test/request-attribute-test-sel1.esp b/src/test/resources/integration-test/request-attribute-test-sel1.esp
new file mode 100644
index 0000000..7de0ad1
--- /dev/null
+++ b/src/test/resources/integration-test/request-attribute-test-sel1.esp
@@ -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.
+-->
+<%-- used by RequestAttributeTest --%>
+<%
+    function /* String */ getServlet() {
+        var servlet = request.getAttribute( "org.apache.sling.api.include.servlet" );
+        if (servlet) {
+            return servlet.servletConfig.servletName;
+        } else {
+            return "null";
+        }
+    }
+%>
+servlet10=<%= getServlet() %>
+resource10=<%= request.getContextPath() + request.getAttribute( "org.apache.sling.api.include.resource" ) %>
+<% sling.include(resource.path, "replaceSelectors=sel3"); %>
+servlet11=<%= getServlet() %>
+resource11=<%= request.getContextPath() + request.getAttribute( "org.apache.sling.api.include.resource" ) %>
diff --git a/src/test/resources/integration-test/request-attribute-test-sel2.esp b/src/test/resources/integration-test/request-attribute-test-sel2.esp
new file mode 100644
index 0000000..359c121
--- /dev/null
+++ b/src/test/resources/integration-test/request-attribute-test-sel2.esp
@@ -0,0 +1,31 @@
+<%--
+ * 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.
+-->
+<%-- used by RequestAttributeTest --%>
+<%
+    function /* String */ getServlet() {
+        var servlet = request.getAttribute( "org.apache.sling.api.include.servlet" );
+        if (servlet) {
+            return servlet.servletConfig.servletName;
+        } else {
+            return "null";
+        }
+    }
+%>
+servlet20=<%= getServlet() %>
+resource20=<%= request.getContextPath() + request.getAttribute( "org.apache.sling.api.include.resource" ) %>
diff --git a/src/test/resources/integration-test/request-attribute-test-sel3.esp b/src/test/resources/integration-test/request-attribute-test-sel3.esp
new file mode 100644
index 0000000..cefcb6d
--- /dev/null
+++ b/src/test/resources/integration-test/request-attribute-test-sel3.esp
@@ -0,0 +1,31 @@
+<%--
+ * 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.
+-->
+<%-- used by RequestAttributeTest --%>
+<%
+    function /* String */ getServlet() {
+        var servlet = request.getAttribute( "org.apache.sling.api.include.servlet" );
+        if (servlet) {
+            return servlet.servletConfig.servletName;
+        } else {
+            return "null";
+        }
+    }
+%>
+servlet30=<%= getServlet() %>
+resource30=<%= request.getContextPath() + request.getAttribute( "org.apache.sling.api.include.resource" ) %>
diff --git a/src/test/resources/integration-test/request-attribute-test.esp b/src/test/resources/integration-test/request-attribute-test.esp
new file mode 100644
index 0000000..4c3c15a
--- /dev/null
+++ b/src/test/resources/integration-test/request-attribute-test.esp
@@ -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.
+-->
+<%-- used by RequestAttributeTest --%>
+<%
+    response.setContentType("text/plain");
+    response.setCharacterEncoding("UTF-8");
+
+    function /* String */ getServlet() {
+        var servlet = request.getAttribute( "org.apache.sling.api.include.servlet" );
+        if (servlet) {
+            return servlet.servletConfig.servletName;
+        } else {
+            return "null";
+        }
+    }
+%>
+servlet00=<%= getServlet() %>
+resource00=<%= request.getAttribute( "org.apache.sling.api.include.resource" ) %>
+<% sling.include(resource.path + "/child", "replaceSelectors=sel1"); %>
+<% sling.include(resource.path, "replaceSelectors=sel2"); %>
+servlet01=<%= getServlet() %>
+resource01=<%= request.getAttribute( "org.apache.sling.api.include.resource" ) %>
diff --git a/src/test/resources/integration-test/sling-logo.png b/src/test/resources/integration-test/sling-logo.png
new file mode 100644
index 0000000..0de4b3a
--- /dev/null
+++ b/src/test/resources/integration-test/sling-logo.png
Binary files differ
diff --git a/src/test/resources/integration-test/testfile.html b/src/test/resources/integration-test/testfile.html
new file mode 100644
index 0000000..e95ba6a
--- /dev/null
+++ b/src/test/resources/integration-test/testfile.html
@@ -0,0 +1 @@
+This is <em>testfile.html</em>
\ No newline at end of file
diff --git a/src/test/resources/integration-test/testfile.js b/src/test/resources/integration-test/testfile.js
new file mode 100644
index 0000000..bc9ede4
--- /dev/null
+++ b/src/test/resources/integration-test/testfile.js
@@ -0,0 +1 @@
+// This is testfile.js
\ No newline at end of file
diff --git a/src/test/resources/integration-test/testfile.json b/src/test/resources/integration-test/testfile.json
new file mode 100644
index 0000000..40487f3
--- /dev/null
+++ b/src/test/resources/integration-test/testfile.json
@@ -0,0 +1 @@
+This is testfile.json
\ No newline at end of file
diff --git a/src/test/resources/integration-test/testfile.txt b/src/test/resources/integration-test/testfile.txt
new file mode 100644
index 0000000..6a61609
--- /dev/null
+++ b/src/test/resources/integration-test/testfile.txt
@@ -0,0 +1 @@
+This is just some text in an ASCII file.
\ No newline at end of file
diff --git a/src/test/resources/integration-test/testfile.xml b/src/test/resources/integration-test/testfile.xml
new file mode 100644
index 0000000..728448a
--- /dev/null
+++ b/src/test/resources/integration-test/testfile.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- 
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ -->
+
+<testfile id="42">
+  <some-element>
+    <child-element id="1"/>
+    <child-element id="2"/>
+  </some-element>
+</testfile> 
diff --git a/src/test/resources/integration-test/testfile.zip b/src/test/resources/integration-test/testfile.zip
new file mode 100644
index 0000000..46cfd31
--- /dev/null
+++ b/src/test/resources/integration-test/testfile.zip
Binary files differ