diff --git a/README.md b/README.md index 186fbaa..c85c6c5 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,10 @@ services: image: junit-image-test:test_container entrypoint: ["/busybox/sh", "./test_container_entrypoint.sh"] environment: - - JAVA_BINARY=/path/to/jdk/in/custom/image/bin/java + - JAVA_HOME=/path/to/jdk/in/custom/image/bin/java - JUNIT_PARAMS=--include-classname com.something.integration.* ``` + +## Pre compose up script + +Sometimes, you may need some logic to run before the compose test containers come up. You can use `pre_compose_up_script` for that purpose. See [examples/pre-compose-up-script-test](examples/pre-compose-up-script-test) for an example. diff --git a/docker_compose/docker_compose_test.bzl b/docker_compose/docker_compose_test.bzl index e2bba3c..4173d96 100644 --- a/docker_compose/docker_compose_test.bzl +++ b/docker_compose/docker_compose_test.bzl @@ -17,29 +17,30 @@ load("@rules_pkg//:pkg.bzl", "pkg_tar") load("@repo_absolute_path//:build_root.bzl", "BUILD_WORKSPACE_DIRECTORY") load("@rules_oci//oci:defs.bzl", "oci_image", "oci_tarball") +common_tags = [ + "docker", # these tests depend on docker + "exclusive", # these tests should run independent of others + "external", # test has an external dependency; disable test caching +] + def docker_compose_test( name, docker_compose_file, docker_compose_test_container, + pre_compose_up_script = "", local_image_targets = "", data = [], tags = [], size = "large", **kwargs): - tags = [ - "external", # test has an external dependency; disable test caching - ] + tags - + tags = common_tags + tags data = data + [ docker_compose_file ] + if len(pre_compose_up_script): + data = data + [ pre_compose_up_script ] native.sh_test( name = name, srcs = ["@rules_docker_compose//docker_compose:docker_compose_test.sh"], - env = { - "WORKSPACE_PATH": BUILD_WORKSPACE_DIRECTORY, - "DOCKER_COMPOSE_FILE": "$(location " + docker_compose_file + ")", - "DOCKER_COMPOSE_TEST_CONTAINER": docker_compose_test_container, - "LOCAL_IMAGE_TARGETS": local_image_targets.replace(":", "/"), - }, + env = _get_env(docker_compose_file, local_image_targets, docker_compose_test_container, pre_compose_up_script), size = size, tags = tags, data = data, @@ -51,6 +52,7 @@ def junit_docker_compose_test( name, docker_compose_file, docker_compose_test_container, + pre_compose_up_script = "", local_image_targets = "", classpath_jars = [], test_image_base = None, @@ -60,86 +62,92 @@ def junit_docker_compose_test( tags = [], size = "large", **kwargs): - tags = [ - "external", # test has an external dependency; disable test caching - ] + tags - + tags = common_tags + tags data = data + [ docker_compose_file ] + if len(pre_compose_up_script): + data = data + [ pre_compose_up_script ] + + if test_image_base == None: + fail("if you are definiing test_srcs, you need to provide a test_image_base") + + # building an uber jar with test srcs & all dependencies + native.java_binary( + name = name + "_uber_jar", + srcs = test_srcs, + testonly = True, + deps = test_deps, + resources = test_deps, + main_class = "not_used", + ) + + # uber jar contains test classes + pkg_tar( + name = name + "_uber_jar_tar", + srcs = [name + "_uber_jar_deploy.jar"], + testonly = True, + ) + + # these are jars that need to be on the classpath for the junit tests to execute + pkg_tar( + name = name + "_required_classpath_jars_tar", + srcs = classpath_jars, + testonly = True, + ) + + # this is what actually runs the junit jar for your test execution + pkg_tar( + name = name + "_test_container_entrypoint", + srcs = ["@rules_docker_compose//docker_compose:test_container_entrypoint.sh"], + ) - # if there are srcs, build a test container that includes the tests - if len(test_srcs): - - if test_image_base == None: - fail("if you are definiing test_srcs, you need to provide a test_image_base") - - # building an uber jar with test srcs & all dependencies - native.java_binary( - name = name + "_uber_jar", - srcs = test_srcs, - testonly = True, - deps = test_deps, - main_class = "not_used", - ) - - # uber jar contains test classes - pkg_tar( - name = name + "_uber_jar_tar", - srcs = [name + "_uber_jar"], - testonly = True, - ) - - # these are jars that need to be on the classpath for the junit tests to execute - pkg_tar( - name = name + "_required_classpath_jars_tar", - srcs = classpath_jars, - testonly = True, - ) - - # this is what actually runs the junit jar for your test execution - pkg_tar( - name = name + "_test_container_entrypoint", - srcs = ["@rules_docker_compose//docker_compose:test_container_entrypoint.sh"], - ) - - oci_image( - name = "java_image", - base = test_image_base, - tars = [ - name + "_uber_jar_tar", - name + "_required_classpath_jars_tar", - name + "_test_container_entrypoint", - ], - testonly = True, - ) - - oci_tarball( - name = docker_compose_test_container, - image = ":java_image", - repo_tags = ["%s:%s" % (native.package_name(), docker_compose_test_container)], - testonly = True, - ) - - # this builds & installs the test image. - native.sh_binary( - name = name + "_integration_test_image_fixture", - srcs = [docker_compose_test_container], - testonly = True, - ) - - data.append(name + "_integration_test_image_fixture") - local_image_targets += "%s:%s" % (native.package_name(), docker_compose_test_container) + oci_image( + name = name.lower() + "_java_image", + base = test_image_base, + tars = [ + name + "_uber_jar_tar", + name + "_required_classpath_jars_tar", + name + "_test_container_entrypoint", + ], + testonly = True, + ) + oci_tarball( + name = docker_compose_test_container, + image = name.lower() + "_java_image", + repo_tags = ["%s:%s" % (native.package_name(), docker_compose_test_container)], + testonly = True, + ) + + # this builds & installs the test image. + native.sh_binary( + name = name + "_integration_test_image_fixture", + srcs = [docker_compose_test_container], + testonly = True, + ) + + data.append(name + "_integration_test_image_fixture") + if len(local_image_targets): + local_image_targets += "," + local_image_targets += "%s:%s" % (native.package_name(), docker_compose_test_container) native.sh_test( name = name, srcs = ["@rules_docker_compose//docker_compose:docker_compose_test.sh"], - env = { - "WORKSPACE_PATH": BUILD_WORKSPACE_DIRECTORY, - "DOCKER_COMPOSE_FILE": "$(location " + docker_compose_file + ")", - "DOCKER_COMPOSE_TEST_CONTAINER": docker_compose_test_container, - "LOCAL_IMAGE_TARGETS": local_image_targets.replace(":", "/"), - }, + env = _get_env(docker_compose_file, local_image_targets, docker_compose_test_container, pre_compose_up_script), size = size, tags = tags, data = data, **kwargs, ) + + +def _get_env(docker_compose_file, local_image_targets, docker_compose_test_container, pre_compose_up_script): + env = { + "WORKSPACE_PATH": BUILD_WORKSPACE_DIRECTORY, + "DOCKER_COMPOSE_FILE": "$(location " + docker_compose_file + ")", + "LOCAL_IMAGE_TARGETS": local_image_targets.replace(":", "/"), + "DOCKER_COMPOSE_TEST_CONTAINER": docker_compose_test_container, + } + + if len(pre_compose_up_script): + env["PRE_COMPOSE_UP_SCRIPT"] = "$(location " + pre_compose_up_script + ")" + return env diff --git a/docker_compose/docker_compose_test.sh b/docker_compose/docker_compose_test.sh index 89b4679..d691a5e 100755 --- a/docker_compose/docker_compose_test.sh +++ b/docker_compose/docker_compose_test.sh @@ -13,14 +13,29 @@ # See the License for the specific language governing permissions and # limitations under the License. +# we should not use "set -e" here because we want the docker-compose down to happen at the end regardless of failure/success. + # start by building any local images that are needed for the docker-compose tests export IFS="," echo $LOCAL_IMAGE_TARGETS for LOCAL_IMAGE_TARGET in $LOCAL_IMAGE_TARGETS; do s="$LOCAL_IMAGE_TARGET.sh" + echo "building $LOCAL_IMAGE_TARGET with $s" $s done +# PRE_COMPOSE_UP_SCRIPT is set +if [[ -n "$PRE_COMPOSE_UP_SCRIPT" ]]; then + # we want to move to the location of the script before executing it + # so paths are relative to it. After the script is executed, we move + # back to the original location. + location=$(pwd) + cd $WORKSPACE_PATH + cd $(dirname $PRE_COMPOSE_UP_SCRIPT) + $(basename $PRE_COMPOSE_UP_SCRIPT) + cd $location +fi + # we need to use the path of the real compose file in the file-tree. # if we use the file from inside the sandbox, symlinks will be used for volume mounted files. ABSOLUTE_COMPOSE_FILE_PATH=$WORKSPACE_PATH/$DOCKER_COMPOSE_FILE diff --git a/docker_compose/test_container_entrypoint.sh b/docker_compose/test_container_entrypoint.sh index c4bceb7..1bd1bc1 100755 --- a/docker_compose/test_container_entrypoint.sh +++ b/docker_compose/test_container_entrypoint.sh @@ -13,22 +13,25 @@ # See the License for the specific language governing permissions and # limitations under the License. -if [[ -z "$JAVA_BINARY" ]]; then - JAVA_BINARY="/usr/bin/java" +if [[ -z "$JAVA_HOME" ]]; then + JAVA_HOME="/usr" fi -TEST_UBER_JAR=$(find ./ -maxdepth 1 -name '*_uber_jar.jar') +TEST_UBER_JAR=$(find ./ -maxdepth 1 -name '*_uber_jar_deploy.jar') JUNIT_PLATFORM_CONSOLE_STANDALONE_JAR=$(find ./ -maxdepth 1 -name '*junit-platform-console-standalone*.jar') # TODO: need to find a better solution than adding all of the jars to the class-path below # The only one we should need to add is the fat jar because it should contain the rest of them.. # However, it seems like we need to add all of the spring/spring-boot jars like this. -JARS=$(find ./ -maxdepth 1 -name '*.jar') +JARS=$(find ./ -maxdepth 1 -name '*.jar' ! -name '*_uber_jar_deploy.jar') CLASS_PATH_STRING="" for JAR in $JARS; do CLASS_PATH_STRING="$CLASS_PATH_STRING --class-path $JAR" done -# JUNIT_PARAMS can be set in their compose file to filter for specific tests +# JUNIT_PARAMS can be set in the docker-compose file to filter for specific tests # e.g. --include-classname com.something.integration.* -$JAVA_BINARY -jar $JUNIT_PLATFORM_CONSOLE_STANDALONE_JAR --class-path $TEST_UBER_JAR --scan-class-path --fail-if-no-tests $CLASS_PATH_STRING $JUNIT_PARAMS +cmd="$JAVA_HOME/bin/java -jar $JUNIT_PLATFORM_CONSOLE_STANDALONE_JAR \ + --scan-class-path --fail-if-no-tests $CLASS_PATH_STRING --class-path $TEST_UBER_JAR $JUNIT_PARAMS" +echo $cmd +$cmd diff --git a/examples/pre-compose-up-script-test/BUILD b/examples/pre-compose-up-script-test/BUILD new file mode 100644 index 0000000..c983eb7 --- /dev/null +++ b/examples/pre-compose-up-script-test/BUILD @@ -0,0 +1,23 @@ +# Copyright (c) 2023, Salesforce, Inc. +# SPDX-License-Identifier: Apache-2 + +# 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. + +load("@rules_docker_compose//docker_compose:docker_compose_test.bzl", "docker_compose_test") + +docker_compose_test( + name = "pre-compose-up-script-test", + docker_compose_file = ":docker-compose.yml", + docker_compose_test_container = "test_container", + pre_compose_up_script = ":src/test/resources/setup_test.sh" +) diff --git a/examples/pre-compose-up-script-test/docker-compose.yml b/examples/pre-compose-up-script-test/docker-compose.yml new file mode 100644 index 0000000..92985ee --- /dev/null +++ b/examples/pre-compose-up-script-test/docker-compose.yml @@ -0,0 +1,21 @@ +# Copyright (c) 2023, Salesforce, Inc. +# SPDX-License-Identifier: Apache-2 + +# 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. + +services: + test_container: + image: gcr.io/distroless/static-debian12:debug + entrypoint: ["cat", "/resources/generated_file.txt"] + volumes: + - ./src/test/resources:/resources diff --git a/examples/pre-compose-up-script-test/src/test/resources/.gitignore b/examples/pre-compose-up-script-test/src/test/resources/.gitignore new file mode 100644 index 0000000..e00b0dc --- /dev/null +++ b/examples/pre-compose-up-script-test/src/test/resources/.gitignore @@ -0,0 +1,4 @@ +# we don't want to check-in the generated file +# because that's what we're actually testing here +# (that the file is generated when the test is executed). +generated_file.txt diff --git a/examples/pre-compose-up-script-test/src/test/resources/setup_test.sh b/examples/pre-compose-up-script-test/src/test/resources/setup_test.sh new file mode 100755 index 0000000..b8abcf6 --- /dev/null +++ b/examples/pre-compose-up-script-test/src/test/resources/setup_test.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -e + +# This file is created as a pre-req to the docker-compose test actually running. +# Locally, the file will always be there but it won't be checked in as it is in .gitignore. +# CI will make sure that the file is generated on every execution. +touch generated_file.txt