|
|
@@ -20,23 +20,20 @@ |
|
|
|
# Helper script to run the acceptance tests, which test a running Nextcloud |
|
|
|
# instance from the point of view of a real user. |
|
|
|
# |
|
|
|
# The acceptance tests are written in Behat so, besides running the tests, this |
|
|
|
# script installs Behat, its dependencies, and some related packages in the |
|
|
|
# "vendor" subdirectory of the acceptance tests. The acceptance tests also use |
|
|
|
# the Selenium server to control a web browser, so the Selenium server is also |
|
|
|
# launched before the tests start in its own Docker container (it will be |
|
|
|
# stopped automatically once the tests end). Finally, the tests expect that a |
|
|
|
# Docker image with the Nextcloud installation to be tested is available, so the |
|
|
|
# script creates it based on the Nextcloud code from the grandparent directory. |
|
|
|
# The acceptance tests are run in its own Docker container; the grandparent |
|
|
|
# directory of the acceptance tests directory (that is, the root directory of |
|
|
|
# the Nextcloud server) is copied to the container and the acceptance tests are |
|
|
|
# run inside it. Once the tests end the container is stopped. The acceptance |
|
|
|
# tests also use the Selenium server to control a web browser, so the Selenium |
|
|
|
# server is also launched before the tests start in its own Docker container (it |
|
|
|
# will be stopped automatically too once the tests end). |
|
|
|
# |
|
|
|
# To perform its job, the script requires the "composer" and "docker" commands |
|
|
|
# to be available. |
|
|
|
# To perform its job, the script requires the "docker" command to be available. |
|
|
|
# |
|
|
|
# The Docker Command Line Interface (the "docker" command) requires special |
|
|
|
# permissions to talk to the Docker daemon, and those permissions are typically |
|
|
|
# available only to the root user. However, you should NOT run this script as |
|
|
|
# root, but as a regular user instead. Please see the Docker documentation to |
|
|
|
# find out how to give access to a regular user to the Docker daemon: |
|
|
|
# available only to the root user. Please see the Docker documentation to find |
|
|
|
# out how to give access to a regular user to the Docker daemon: |
|
|
|
# https://docs.docker.com/engine/installation/linux/linux-postinstall/ |
|
|
|
# |
|
|
|
# Note, however, that being able to communicate with the Docker daemon is the |
|
|
@@ -46,21 +43,10 @@ |
|
|
|
# https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface |
|
|
|
# |
|
|
|
# Finally, take into account that this script will automatically remove the |
|
|
|
# Docker containers named "selenium-nextcloud-local-test-acceptance", |
|
|
|
# "nextcloud-local-test-acceptance" and |
|
|
|
# "nextcloud-local-test-acceptance-[0-9a-f.]*", and the Docker image tagged as |
|
|
|
# "nextcloud-local-test-acceptance:latest", even if the script did not create |
|
|
|
# them (probably you will not have containers nor images with those names, but |
|
|
|
# just in case). |
|
|
|
|
|
|
|
# Installs Behat and its dependencies. |
|
|
|
# |
|
|
|
# Behat and its dependencies will be installed in the "vendor" subdirectory of |
|
|
|
# the directory of the script. |
|
|
|
function prepareBehat() { |
|
|
|
echo "Installing Behat and dependencies" |
|
|
|
composer install |
|
|
|
} |
|
|
|
# Docker containers named "selenium-nextcloud-local-test-acceptance" and |
|
|
|
# "nextcloud-local-test-acceptance", even if the script did not create them |
|
|
|
# (probably you will not have containers nor images with those names, but just |
|
|
|
# in case). |
|
|
|
|
|
|
|
# Launches the Selenium server in a Docker container. |
|
|
|
# |
|
|
@@ -70,18 +56,12 @@ function prepareBehat() { |
|
|
|
# the latest one, but an older version known to work. |
|
|
|
# |
|
|
|
# The acceptance tests expect the Selenium server to be accessible at |
|
|
|
# "127.0.0.1:4444", so the 4444 port of the container is mapped to the 4444 port |
|
|
|
# of the host. |
|
|
|
# |
|
|
|
# The Nextcloud server has to be accessed at "127.0.0.1" by the Selenium server |
|
|
|
# (as that is the only trusted domain by default), so the Nextcloud server |
|
|
|
# containers have to be connected to the network of the Selenium server |
|
|
|
# container (another option would be to connect the Selenium server to the host |
|
|
|
# network, but messing with the host network is better avoided if possible). The |
|
|
|
# acceptance tests themselves also need access to the Nextcloud server to ensure |
|
|
|
# that it is ready before starting each scenario, so the 80 port of the Selenium |
|
|
|
# server is mapped to the 80 port of the host (it is not possible to map the |
|
|
|
# port in the container that connects to the network of another container). |
|
|
|
# "127.0.0.1:4444"; as the Selenium server container and the container in which |
|
|
|
# the acceptance tests are run share the same network nothing else needs to be |
|
|
|
# done for the acceptance tests to access the Selenium server and for the |
|
|
|
# Selenium server to access the Nextcloud server. However, in order to ensure |
|
|
|
# from this script that the Selenium server was started the 4444 port of its |
|
|
|
# container is mapped to the 4444 port of the host. |
|
|
|
# |
|
|
|
# Besides the Selenium server, the Docker image also provides a VNC server, so |
|
|
|
# the 5900 port of the container is also mapped to the 5900 port of the host. |
|
|
@@ -90,7 +70,7 @@ function prepareBehat() { |
|
|
|
# script exits (see cleanUp). If the Selenium server can not be started then the |
|
|
|
# script will be exited immediately with an error state; the most common cause |
|
|
|
# for the Selenium server to fail to start is that another server is already |
|
|
|
# running in the default port. |
|
|
|
# using the mapped ports in the host. |
|
|
|
# |
|
|
|
# As the web browser is run inside the Docker container it is not visible by |
|
|
|
# default. However, it can be viewed using VNC (for example, |
|
|
@@ -99,67 +79,37 @@ function prepareSelenium() { |
|
|
|
SELENIUM_CONTAINER=selenium-nextcloud-local-test-acceptance |
|
|
|
|
|
|
|
echo "Starting Selenium server" |
|
|
|
docker run --detach --name=$SELENIUM_CONTAINER --publish 80:80 --publish 4444:4444 --publish 5900:5900 selenium/standalone-firefox-debug:2.53.1-beryllium |
|
|
|
docker run --detach --name=$SELENIUM_CONTAINER --publish 4444:4444 --publish 5900:5900 selenium/standalone-firefox-debug:2.53.1-beryllium |
|
|
|
|
|
|
|
echo "Waiting for Selenium server to be ready" |
|
|
|
if ! timeout 10s bash -c "while ! curl 127.0.0.1:4444 >/dev/null 2>&1; do sleep 1; done"; then |
|
|
|
echo "Could not start Selenium server; running" \ |
|
|
|
"\"docker run --rm --publish 80:80 --publish 4444:4444 --publish 5900:5900 selenium/standalone-firefox-debug:2.53.1-beryllium\"" \ |
|
|
|
"\"docker run --rm --publish 4444:4444 --publish 5900:5900 selenium/standalone-firefox-debug:2.53.1-beryllium\"" \ |
|
|
|
"could give you a hint of the problem" |
|
|
|
|
|
|
|
exit 1 |
|
|
|
fi |
|
|
|
} |
|
|
|
|
|
|
|
# Creates a Docker image to be used in Behat by NextcloudTestServerContext based |
|
|
|
# on the local Nextcloud directory. |
|
|
|
# Creates a Docker container to run both the acceptance tests and the Nextcloud |
|
|
|
# server used by them. |
|
|
|
# |
|
|
|
# NextcloudTestServerContext creates and destroys a Docker container for each |
|
|
|
# acceptance test run, and the image that the container is created from must |
|
|
|
# provide an installed copy of Nextcloud with certain configuration (like an |
|
|
|
# "admin" user with an "admin" password, or local data storage). This function |
|
|
|
# creates that Docker image based on the Nextcloud code from the grandparent |
|
|
|
# directory, although ignoring any configuration or data that it may provide |
|
|
|
# (for example, if that directory was used directly to deploy a Nextcloud |
|
|
|
# instance in a web server). As the Nextcloud code is copied to the image |
|
|
|
# instead of referenced the original code can be modified while the acceptance |
|
|
|
# tests are running without interfering in them. |
|
|
|
# |
|
|
|
# Besides the Docker image to be used by the acceptance tests, which is removed |
|
|
|
# automatically when the script exits, this function creates another image, |
|
|
|
# that the other one will be based on, which is not removed when the script |
|
|
|
# exits. Building this parent image could be a slow process, so it is kept built |
|
|
|
# instead of removing it every time to speed up the launch of the acceptance |
|
|
|
# tests. |
|
|
|
# This function starts a Docker container with a copy the Nextcloud code from |
|
|
|
# the grandparent directory, although ignoring any configuration or data that it |
|
|
|
# may provide (for example, if that directory was used directly to deploy a |
|
|
|
# Nextcloud instance in a web server). As the Nextcloud code is copied to the |
|
|
|
# container instead of referenced the original code can be modified while the |
|
|
|
# acceptance tests are running without interfering in them. |
|
|
|
function prepareDocker() { |
|
|
|
NEXTCLOUD_LOCAL_IMAGE=nextcloud-local-test-acceptance |
|
|
|
NEXTCLOUD_LOCAL_CONTAINER=nextcloud-local-test-acceptance |
|
|
|
|
|
|
|
# To create the Docker image to be used by the acceptance tests first a |
|
|
|
# parent image is created. This parent image provides a system in which a |
|
|
|
# Nextcloud server could be installed. Then, that parent image is run in a |
|
|
|
# container in which the relevant code from the grandparent directory is |
|
|
|
# copied; once the code is copied, the Nextcloud server is installed and |
|
|
|
# configured as needed inside the container. Finally, the image to be used |
|
|
|
# by the acceptance tests is generated by persisting the container to a new |
|
|
|
# image. |
|
|
|
# |
|
|
|
# The image to be used by the acceptance tests could have been created just |
|
|
|
# with a Dockerfile by adding the relevant code to the build context before |
|
|
|
# starting the build and then using the ADD command in the Dockerfile (plus |
|
|
|
# running the commands to install and configure the server as needed). In |
|
|
|
# fact, standard Docker practices favor the creation of images through |
|
|
|
# Dockerfiles to get a reproducible build. However, in this case I felt that |
|
|
|
# it would go against that reproducible spirit of Dockerfiles, as an |
|
|
|
# additional .tar file would have to be explicitly created each time before |
|
|
|
# building the image, and that file would probably be different between |
|
|
|
# different builds, thus resulting in a different image each time. Therefore |
|
|
|
# I think that the current approach is better suited for this scenario. |
|
|
|
|
|
|
|
echo "Building Docker parent image" |
|
|
|
docker build --tag $NEXTCLOUD_LOCAL_IMAGE:parent - < docker/nextcloud-local-parent/Dockerfile |
|
|
|
|
|
|
|
docker run --detach --name=$NEXTCLOUD_LOCAL_CONTAINER $NEXTCLOUD_LOCAL_IMAGE:parent |
|
|
|
echo "Starting the Nextcloud container" |
|
|
|
# As the Nextcloud server container uses the network of the Selenium server |
|
|
|
# container the Nextcloud server can be accessed at "127.0.0.1" from the |
|
|
|
# Selenium server. |
|
|
|
# The container exits immediately if no command is given, so a Bash session |
|
|
|
# is created to prevent that. |
|
|
|
docker run --detach --name=$NEXTCLOUD_LOCAL_CONTAINER --network=container:$SELENIUM_CONTAINER --interactive --tty nextcloudci/php7.0:php7.0-7 bash |
|
|
|
|
|
|
|
# Use the $TMPDIR or, if not set, fall back to /tmp. |
|
|
|
NEXTCLOUD_LOCAL_TAR="$(mktemp --tmpdir="${TMPDIR:-/tmp}" --suffix=.tar nextcloud-local-XXXXXXXXXX)" |
|
|
@@ -168,24 +118,16 @@ function prepareDocker() { |
|
|
|
# "docker cp" does not take them into account (the extracted files are set |
|
|
|
# to root). |
|
|
|
echo "Copying local Git working directory of Nextcloud to the container" |
|
|
|
tar --create --file="$NEXTCLOUD_LOCAL_TAR" --exclude=".git" --exclude="./build" --exclude="./config/config.php" --exclude="./data" --exclude="./tests" --directory=../../ . |
|
|
|
tar --append --file="$NEXTCLOUD_LOCAL_TAR" --directory=../../ build/acceptance/installAndConfigureServer.sh |
|
|
|
|
|
|
|
docker cp - $NEXTCLOUD_LOCAL_CONTAINER:/var/www/html/ < "$NEXTCLOUD_LOCAL_TAR" |
|
|
|
docker exec $NEXTCLOUD_LOCAL_CONTAINER chown -R www-data:www-data /var/www/html/ |
|
|
|
tar --create --file="$NEXTCLOUD_LOCAL_TAR" --exclude=".git" --exclude="./config/config.php" --exclude="./data" --exclude="./tests" --directory=../../ . |
|
|
|
|
|
|
|
echo "Installing Nextcloud in the container" |
|
|
|
docker exec --user www-data $NEXTCLOUD_LOCAL_CONTAINER build/acceptance/installAndConfigureServer.sh |
|
|
|
docker exec $NEXTCLOUD_LOCAL_CONTAINER mkdir /nextcloud |
|
|
|
docker cp - $NEXTCLOUD_LOCAL_CONTAINER:/nextcloud/ < "$NEXTCLOUD_LOCAL_TAR" |
|
|
|
|
|
|
|
echo "Creating Docker image to be used in acceptance tests" |
|
|
|
docker commit --message "Nextcloud installed from the local Git working directory" $NEXTCLOUD_LOCAL_CONTAINER $NEXTCLOUD_LOCAL_IMAGE |
|
|
|
|
|
|
|
# Once the image to be used by the acceptance tests is created the container |
|
|
|
# is no longer needed, so it can be stopped and removed. |
|
|
|
docker stop $NEXTCLOUD_LOCAL_CONTAINER |
|
|
|
# Although the parent Nextcloud image does not define a volume "--volumes" |
|
|
|
# is used anyway just in case any of its ancestor images does. |
|
|
|
docker rm --volumes $NEXTCLOUD_LOCAL_CONTAINER |
|
|
|
# run-local.sh expects a Git repository to be available in the root of the |
|
|
|
# Nextcloud server, but it was excluded when the Git working directory was |
|
|
|
# copied to the container to avoid copying the large and unneeded history of |
|
|
|
# the repository. |
|
|
|
docker exec $NEXTCLOUD_LOCAL_CONTAINER bash -c "cd nextcloud && git init" |
|
|
|
} |
|
|
|
|
|
|
|
# Removes/stops temporal elements created/started by this script. |
|
|
@@ -202,8 +144,6 @@ function cleanUp() { |
|
|
|
rm $NEXTCLOUD_LOCAL_TAR |
|
|
|
fi |
|
|
|
|
|
|
|
# If the script run successfully the container should have already been |
|
|
|
# removed; this is needed only when an error happened. |
|
|
|
# The name filter must be specified as "^/XXX$" to get an exact match; using |
|
|
|
# just "XXX" would match every name that contained "XXX". |
|
|
|
if [ -n "$(docker ps --all --quiet --filter name="^/$NEXTCLOUD_LOCAL_CONTAINER$")" ]; then |
|
|
@@ -211,21 +151,6 @@ function cleanUp() { |
|
|
|
docker rm --volumes --force $NEXTCLOUD_LOCAL_CONTAINER |
|
|
|
fi |
|
|
|
|
|
|
|
# In case of failure (like calling a method that does not exist on an |
|
|
|
# object) the tests would be aborted without removing the containers created |
|
|
|
# by NextcloudTestServerContext; if that happens those dangling containers |
|
|
|
# are removed here. |
|
|
|
DANGLING_CONTAINERS_CREATED_BY_ACCEPTANCE_TESTS="$(docker ps --all --quiet --filter name="^/$NEXTCLOUD_LOCAL_CONTAINER-[0-9a-f.]*$" --filter ancestor="$NEXTCLOUD_LOCAL_IMAGE:parent")" |
|
|
|
if [ -n "$DANGLING_CONTAINERS_CREATED_BY_ACCEPTANCE_TESTS" ]; then |
|
|
|
echo "Removing Docker containers matching $NEXTCLOUD_LOCAL_CONTAINER-[0-9a-f.]*" |
|
|
|
docker rm --volumes --force $DANGLING_CONTAINERS_CREATED_BY_ACCEPTANCE_TESTS |
|
|
|
fi |
|
|
|
|
|
|
|
if [ -n "$(docker images --quiet $NEXTCLOUD_LOCAL_IMAGE:latest)" ]; then |
|
|
|
echo "Removing Docker image $NEXTCLOUD_LOCAL_IMAGE:latest" |
|
|
|
docker rmi $NEXTCLOUD_LOCAL_IMAGE:latest |
|
|
|
fi |
|
|
|
|
|
|
|
if [ -n "$(docker ps --all --quiet --filter name="^/$SELENIUM_CONTAINER$")" ]; then |
|
|
|
echo "Removing Docker container $SELENIUM_CONTAINER" |
|
|
|
docker rm --volumes --force $SELENIUM_CONTAINER |
|
|
@@ -238,17 +163,15 @@ set -o errexit |
|
|
|
# Execute cleanUp when the script exits, either normally or due to an error. |
|
|
|
trap cleanUp EXIT |
|
|
|
|
|
|
|
# Ensure working directory is script directory, as some actions (like installing |
|
|
|
# Behat through Composer or generating the Nextcloud image for Docker) expect |
|
|
|
# that. |
|
|
|
# Ensure working directory is script directory, as some actions (like copying |
|
|
|
# the Git working directory to the container) expect that. |
|
|
|
cd "$(dirname $0)" |
|
|
|
|
|
|
|
# If no parameter is provided to this script all the acceptance tests are run. |
|
|
|
SCENARIO_TO_RUN=$1 |
|
|
|
|
|
|
|
prepareBehat |
|
|
|
prepareSelenium |
|
|
|
prepareDocker |
|
|
|
|
|
|
|
echo "Running tests" |
|
|
|
vendor/bin/behat $SCENARIO_TO_RUN |
|
|
|
docker exec $NEXTCLOUD_LOCAL_CONTAINER bash -c "cd nextcloud && build/acceptance/run-local.sh $SCENARIO_TO_RUN" |