//g;s/| .*<\/td> | //g;s///g;s/<\/t.>//g'
+    assert 'default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';' \
+      bash -c "curl -fsSL --user \"admin:$(get_jenkins_password)\" $(get_jenkins_url)/systemInfo | sed 's/<\/tr>/<\/tr>\'$'\n/g' | grep ' | hudson.model.DirectoryBrowserSupport.CSP' | sed -e '${sed_expr}'"
+    assert 'Europe/Madrid' \
+      bash -c "curl -fsSL --user \"admin:$(get_jenkins_password)\" $(get_jenkins_url)/systemInfo | sed 's/<\/tr>/<\/tr>\'$'\n/g' | grep ' | user.timezone' | sed -e '${sed_expr}'"
+}
+
+@test "clean test containers" {
+    cleanup $SUT_CONTAINER
+}
diff --git a/jenkins/tests/test_helpers.bash b/jenkins/tests/test_helpers.bash
new file mode 100644
index 0000000..eb67f45
--- /dev/null
+++ b/jenkins/tests/test_helpers.bash
@@ -0,0 +1,84 @@
+#!/bin/bash
+
+# check dependencies
+(
+    type docker &>/dev/null || ( echo "docker is not available"; exit 1 )
+    type curl &>/dev/null || ( echo "curl is not available"; exit 1 )
+)>&2
+
+# Assert that $1 is the outputof a command $2
+function assert {
+    local expected_output=$1
+    shift
+    local actual_output
+    actual_output=$("$@")
+    actual_output="${actual_output//[$'\t\r\n']}" # remove newlines
+    if ! [ "$actual_output" = "$expected_output" ]; then
+        echo "expected: \"$expected_output\""
+        echo "actual:   \"$actual_output\""
+        false
+    fi
+}
+
+# Retry a command $1 times until it succeeds. Wait $2 seconds between retries.
+function retry {
+    local attempts=$1
+    shift
+    local delay=$1
+    shift
+    local i
+
+    for ((i=0; i < attempts; i++)); do
+        run "$@"
+        if [ "$status" -eq 0 ]; then
+            return 0
+        fi
+        sleep $delay
+    done
+
+    echo "Command \"$*\" failed $attempts times. Status: $status. Output: $output" >&2
+    false
+}
+
+function docker_build {
+    if [ -n "$JENKINS_VERSION" ]; then
+        docker build --build-arg JENKINS_VERSION=$JENKINS_VERSION --build-arg JENKINS_SHA=$JENKINS_SHA "$@"
+    else
+        docker build "$@"
+    fi
+}
+
+function get_jenkins_url {
+    if [ -z "${DOCKER_HOST}" ]; then
+        DOCKER_IP=localhost
+    else
+        DOCKER_IP=$(echo "$DOCKER_HOST" | sed -e 's|tcp://\(.*\):[0-9]*|\1|')
+    fi
+    echo "http://$DOCKER_IP:$(docker port "$SUT_CONTAINER" 8080 | cut -d: -f2)"
+}
+
+function get_jenkins_password {
+    docker logs "$SUT_CONTAINER" 2>&1 | grep -A 2 "Please use the following password to proceed to installation" | tail -n 1
+}
+
+function test_url {
+    run curl --user "admin:$(get_jenkins_password)" --output /dev/null --silent --head --fail --connect-timeout 30 --max-time 60 "$(get_jenkins_url)$1"
+    if [ "$status" -eq 0 ]; then
+        true
+    else
+        echo "URL $(get_jenkins_url)$1 failed" >&2
+        echo "output: $output" >&2
+        false
+    fi
+}
+
+function cleanup {
+    docker kill "$1" &>/dev/null ||:
+    docker rm -fv "$1" &>/dev/null ||:
+}
+
+function unzip_manifest {
+    local plugin=$1
+    local work=$2
+    bash -c "docker run --rm -v $work:/var/jenkins_home --entrypoint unzip $SUT_IMAGE -p /var/jenkins_home/plugins/$plugin META-INF/MANIFEST.MF | tr -d '\r'"
+}
diff --git a/jenkins/tests/upgrade-plugins/Dockerfile b/jenkins/tests/upgrade-plugins/Dockerfile
new file mode 100644
index 0000000..dfe81de
--- /dev/null
+++ b/jenkins/tests/upgrade-plugins/Dockerfile
@@ -0,0 +1,3 @@
+FROM bats-jenkins
+
+RUN /usr/local/bin/install-plugins.sh maven-plugin:2.13 ant:1.2
diff --git a/jenkins/update-official-library.sh b/jenkins/update-official-library.sh
new file mode 100644
index 0000000..07e3b1f
--- /dev/null
+++ b/jenkins/update-official-library.sh
@@ -0,0 +1,36 @@
+#!/bin/bash -eu
+
+# Generate the Docker official-images file
+
+sha() {
+    local branch=$1
+    git rev-parse $branch
+}
+
+version_from_dockerfile() {
+    local branch=$1
+    git show $branch:Dockerfile | grep JENKINS_VERSION: | sed -e 's/.*:-\(.*\)}/\1/'
+}
+
+master_sha=$(sha master)
+alpine_sha=$(sha alpine)
+
+master_version=$(version_from_dockerfile master)
+alpine_version=$(version_from_dockerfile alpine)
+
+if ! [ "$master_version" == "$alpine_version" ]; then
+    echo "Master version '$master_version' does not match alpine version '$alpine_version'"
+    exit 1
+fi
+
+cat << EOF > ../official-images/library/jenkins
+# maintainer: Nicolas De Loof  (@ndeloof)
+# maintainer: Michael Neale  (@michaelneale)
+# maintainer: Carlos Sanchez  (@carlossg)
+
+latest: git://github.com/jenkinsci/jenkins-ci.org-docker@$master_sha
+$master_version: git://github.com/jenkinsci/jenkins-ci.org-docker@$master_sha
+
+alpine: git://github.com/jenkinsci/jenkins-ci.org-docker@$alpine_sha
+$alpine_version-alpine: git://github.com/jenkinsci/jenkins-ci.org-docker@$alpine_sha
+EOF |  |