The Gradle Enterprise Test Distribution Agent executes tests triggered from the Test Distribution Gradle plugin on remote machines.

Use of the Gradle Enterprise Test Distribution Agent software is subject to the Gradle Enterprise Software Agreement.

Agents need to be connected to a Gradle Enterprise server.

The Gradle Enterprise Test Distribution Agent is distributed as a Docker image via Docker Hub, and as a executable JAR. Both distributions offer the same functionality.

Requirements

CPU & memory

The agent itself needs about 128 MB of memory and does not require significant CPU resources. However, you need to determine the total memory and CPU resources depending on the types of tests you intend to run on the agent. Two CPU cores and 2 GB of memory are a good starting point for tests that are not particularly resource-intensive. If your tests start additional external processes, you’ll likely need more. Thus, you should monitor CPU and memory consumption of an agent while it’s executing a typical test workload.

Disk usage

The agent uses a local file cache to store JAR files and other artifacts that are required to execute tests. The cache directory is cleaned up periodically so it does not grow indefinitely. How much space you’ll need depends on your tests and how often you’ve configured the cache directory to be cleaned up. Usually, a few hundred MB should be sufficient. We recommend monitoring the directory size over the course of the cache’s retention period.

Network

The agent requires a reasonably fast and stable connection to the Gradle Enterprise server in order to operate efficiently. While running, the agent maintains a persistent WebSocket connection over default HTTP/HTTPS ports to the Gradle Enterprise server.

In case your agents cannot connect to the Gradle Enterprise server, please ensure all load balancers and proxies that are used between both ends support WebSocket connections.

If the connection is lost, e.g. when the server is restarted, the agent will periodically attempt to reconnect. Since all communication goes through the Gradle Enterprise server, the agent does not need a direct connection to the machine that initiated test execution, e.g. the developer workstation or build server running the Gradle build, or vice versa. Moreover, since the connection to the Gradle Enterprise server is initiated by the agent, it can be deployed to an internal network and does not need to be addressable from machines running builds.

Security

Test distribution allows remote code execution inside your infrastructure for authorized Gradle Enterprise users. This is comparable to CI jobs which also execute tests that could theoretically run any command on the remote host. In addition, test code will be able to access the local file system including the local file cache which might include artifacts of other projects that have previously had their tests executed on the same agent. Thus, you should treat the infrastructure you run test distribution agents on similarly to those of regular CI agents.

Installation

JAR

You can download version 1.1.2 of the JAR here. Older versions of the JAR can be found in the appendix below.

The agent requires at least Java 11 to run and supports Linux, macOS, and Windows. Moreover, you need to specify the server and registration key parameters that are required to connect and register with the Gradle Enterprise server.

java -Xms64m -Xmx64m -XX:MaxMetaspaceSize=64m \     (1)
    --illegal-access=deny \                         (2)
    --add-opens java.base/java.lang=ALL-UNNAMED \
    --add-opens java.base/java.util=ALL-UNNAMED \
    -jar gradle-enterprise-test-distribution-agent-1.1.2.jar \
    --server https://«gradle-enterprise-hostname» \
    --registration-key «registration-key»           (3)
1 Minimum required Java memory settings
2 Options to prevent warnings about illegal reflective access on Java 11
3 Registration key generated via Gradle Enterprise administration

You will see output similar to the following:

[…] Skipping cleanup of local file cache (next due on […])
[…] Successfully registered with https://«gradle-enterprise-hostname» (will be refreshed in PT1H)
[…] Agent (v1.1.2) started and connected to https://«gradle-enterprise-hostname»

Docker

With Docker installed, you can start an agent using the following command:

docker run --detach \
    --env TEST_DISTRIBUTION_AGENT_OPTS="-Xms64m -Xmx64m -XX:MaxMetaspaceSize=64m" \ (1)
    gradle/gradle-enterprise-test-distribution-agent:1.1.2 \
    --server https://«gradle-enterprise-hostname» \
    --registration-key «registration-key»                                           (2)
1 Minimum required Java memory settings
2 Registration key generated via Gradle Enterprise administration

Alternatively, you can use environment variables to configure the agent:

docker run --detach \
    --env TEST_DISTRIBUTION_AGENT_OPTS="-Xms64m -Xmx64m -XX:MaxMetaspaceSize=64m" \
    --env TEST_DISTRIBUTION_AGENT_SERVER=https://«gradle-enterprise-hostname» \
    --env TEST_DISTRIBUTION_AGENT_REGISTRATION_KEY=«registration-key» \
    gradle/gradle-enterprise-test-distribution-agent:1.1.2

The default Docker image has AdoptOpenJDK 11 installed. You can extend the image should you wish to install additional JDKs or other software.

Airgapped hosts

In order to install the agent Docker image on a host that is not connected to the Internet (i.e. airgapped), you will need to first obtain the image on an Internet connected host, then transfer it to the airgapped destination.

  1. On the non-airgapped system, pull down the latest docker image for the node and export it to a file

    docker pull gradle/gradle-enterprise-test-distribution-agent:1.1.2
    docker save gradle/gradle-enterprise-test-distribution-agent:1.1.2 \
        --output gradle-enterprise-test-distribution-agent.tar
  2. Copy this file across to the airgapped host, and then import the image into docker

    docker load --input gradle-enterprise-test-distribution-agent.tar

The agent can then be started and configured on the airgapped host in the same manner as a non-airgapped install.

Kubernetes

Below is a sample Kubernetes manifest for deploying agents to a Kubernetes cluster. You may need to adjust its configuration, e.g. the configured CPU and memory requirements, based on the needs of your tests.

---
# kind: scheduler-kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gradle-enterprise-test-distribution-agent
  labels:
    app: gradle-enterprise
    component: test-distribution-agent
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gradle-enterprise
      component: test-distribution-agent
  template:
    metadata:
      labels:
        app: gradle-enterprise
        component: test-distribution-agent
    spec:
      securityContext:
        runAsUser: 999
        runAsGroup: 0
        fsGroup: 0
      containers:
        - name: gradle-enterprise-test-distribution-agent
          image: gradle/gradle-enterprise-test-distribution-agent:1.1.2
          resources:
            requests:
              memory: 1Gi
              cpu: '2'
            limits:
              memory: 4Gi
              cpu: '2'
          env:
            - name: TEST_DISTRIBUTION_AGENT_OPTS
              value: "-Xms64m -Xmx64m -XX:MaxMetaspaceSize=64m"
            - name: TEST_DISTRIBUTION_AGENT_SERVER
              value: https://«gradle-enterprise-hostname»
            - name: TEST_DISTRIBUTION_AGENT_REGISTRATION_KEY
              value: «registration-key»
Prior to Kubernetes v1.9, the deployment apiVersion: apps/v1 should be apiVersion: apps/v1beta1.

Configuration

All configuration options can be specified via command-line arguments or environment variables whereby the former take precendence over the latter.

Registration

There are two mandatory parameters (environment variables) that are used to register with the Gradle Enterprise server on startup:

-s/--server https://«gradle-enterprise-hostname» (env: TEST_DISTRIBUTION_AGENT_SERVER)

The URL of the Gradle Enterprise server the agent should connect to

-r/--registration-key «registration-key» (env: TEST_DISTRIBUTION_AGENT_REGISTRATION_KEY)

The registration key to use for authenticating with the Gradle Enterprise server

The agent sends the registration key to the Gradle Enterprise server when starting up and once every hour to renew its registration. If the registration key is invalid or has been revoked by a Gradle Enterprise administrator, the agent will print an error message and exit with a non-zero status code.

By default, the agent will not allow connections to Gradle Enterprise if the server presents an untrusted certificate (e.g. self-signed). In order to allow such connections, you’ll have to use the following parameter (environment variable):

--allow-untrusted true/false (env: TEST_DISTRIBUTION_AGENT_ALLOW_UNTRUSTED)

Allow/forbid connecting to servers with untrusted (e.g. self signed) SSL certificates (defaults to false)

Enabling this option is a security risk as it makes it easier for a third party to intercept communication between the agent and Gradle Enterprise. It should only be used as a short term workaround until the server can be configured with a trusted certificate.

Finally, you may specify the agent name that will be shown on the Gradle Enterprise Administration pages:

-n/--name «agent-name» (env: TEST_DISTRIBUTION_AGENT_NAME)

Descriptive agent name (defaults to hostname)

Capabilities

When registering with Gradle Enterprise upon startup, the agents report a set of capabilities that will be matched against the requirements of test tasks. Please refer to the Test Distribution Gradle plugin user manual for details.

The agent auto-detects the operating system it is running on (currently supported are Linux, macOS, and Windows) and adds os=linux, os=macos, or os=windows to the set of capabilities.

Moreover, the agent infers installed JDKs from environment variables that match the JDK\d\d? regex and adds a capability for each of them. For example, if JDK8 and JDK11 are set to the paths of their corresponding Java home directories, the agent will automatically add jdk=8 and jdk=11 to the set of capabilities.

If you want to install additional software on a subset of your agents and use that as a criterion when selecting agents for test execution, you can use the following parameter (environment variable):

-c/--capabilities «capability»(,«capability»)* (env: TEST_DISTRIBUTION_AGENT_CAPABILITIES)

Comma-separated list of agent capabilities to match against build requirements

Capabilities may only contain alphanumeric characters, dashes, underscores, periods, and a single equals sign.

For example, the following invocation would make the agent register with the additional docker and postgres=12 capabilities:

java -jar gradle-enterprise-test-distribution-agent-1.1.2.jar […] \
     --capabilities docker,postgres=12

While the exact semantics are up to you, this might indicate that the tests on that agent can use Docker and PostgreSQL in version 12.

Local file cache

The following parameters (environment variables) can be used to configure the local file cache:

--cache-dir «dir» (env: TEST_DISTRIBUTION_AGENT_CACHE_DIR)

Directory to use for the local file cache (defaults to «user-home»/.gradle-enterprise-test-distribution-agent/file-cache)

--cache-cleanup true/false (env: TEST_DISTRIBUTION_AGENT_CACHE_CLEANUP)

Enable/disable cleanup of the local file cache (defaults to true)

--cache-cleanup-interval «duration» (env: TEST_DISTRIBUTION_AGENT_CACHE_CLEANUP_INTERVAL)

Interval in which the local file cache should be cleaned up (defaults to PT24H, i.e. 24 hours)

--cache-retention-period «duration» (env: TEST_DISTRIBUTION_AGENT_CACHE_RETENTION_PERIOD)

Period for which entries in the local file cache should be retained (defaults to PT168H, i.e. 7 days)

Sharing the local file cache among several agents running on the same host is currently not supported. If you are running more than one agent on the same host make sure to configure individual cache directories for each agent or use the Docker image.

Appendix A: Release history

1.1.2

31st July 2020
  • Downloads that fail due to unexpectedly closed connections are now retried

  • Download failures are reported to the build in all cases

1.1.1

29th July 2020
  • Downloaded files are now always closed before storing them in the local file cache

1.1

27th July 2020
  • Input files are now downloaded in parallel from the file cache on the Gradle Enterprise server instead of being requested from connected builds directly

  • Agent jar is published alongside its signature

  • Improved retry handling in case of connection errors

  • Docker image no longer uses the JAVA_OPTS environment variable to avoid inheriting it to test VMs and their child processes

1.0

5th May 2020
  • Initial release

Appendix B: JAR downloads

Appendix C: Compatibility with Gradle Enterprise

Compatibility between versions of Gradle Enterprise and the Gradle Enterprise Test Distribution Agent can be found here.

Appendix D: Extending the Docker image

The Docker image is based on adoptopenjdk:11-jdk-hotspot which is based on Ubuntu so installing additional dependencies is easy. A common use case is to install additional JDKs or other software packages. In the below example, OpenJDK 8 is added along with the zip and unzip Ubuntu packages.

FROM gradle/gradle-enterprise-test-distribution-agent:1.1.2

# Switch to root user for installing packages
USER root

# Install JDK8
RUN set -eux; \
    ESUM='f39b523c724d0e0047d238eb2bb17a9565a60574cf651206c867ee5fc000ab43'; \
    BINARY_URL='https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u242-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u242b08.tar.gz'; \
    curl -LfsSo /tmp/openjdk-8.tar.gz ${BINARY_URL}; \
    echo "${ESUM} */tmp/openjdk-8.tar.gz" | sha256sum -c -; \
    mkdir -p /opt/java/openjdk-8; \
    cd /opt/java/openjdk-8; \
    tar -xf /tmp/openjdk-8.tar.gz --strip-components=1; \
    rm -rf /tmp/openjdk-8.tar.gz;

ENV JDK8=/opt/java/openjdk-8

# Install additional packages
ENV DEBIAN_FRONTEND noninteractive
RUN apt update && apt install -y --no-install-recommends zip unzip

# Switch back to application user
USER gradle

Appendix E: Dealing with tests that start Docker containers

Developers nowadays rely on Docker containers being started from inside their tests in order to test integration with external services. Frameworks like Testcontainers provide Java APIs that make this even easier. Depending on the deployment model you chose, you need to take different steps in order to support executing Docker-based tests on Test Distribution Agents.

In case you decided to deploy the JAR directly you need to make sure that:

  • Docker is installed on the host executing the agent application.

  • The user executing the agent application has sufficient permissions to use Docker.

In case you decided for a Docker-based deployment you need to make Docker available inside the Test Distribution Agent Docker container. The Testcontainers documentation provides more information about patterns that can be used to do this.

Appendix F: Verifying the signature of the agent jar

(agent 1.0.1+)

The agent jar is published to docs.gradle.com alongside its signature. The public key is published to http://pool.sks-keyservers.net and https://keys.openpgp.org. You can verify the signature as follows:

curl -OL https://docs.gradle.com/enterprise/test-distribution-agent/jar/gradle-enterprise-test-distribution-agent-1.1.2.jar
curl -OL https://docs.gradle.com/enterprise/test-distribution-agent/jar/gradle-enterprise-test-distribution-agent-1.1.2.jar.asc
gpg --keyserver keys.openpgp.org --recv-key 314FE82E5A4C5377BCA2EDEC5208812E1E4A6DB0
gpg --verify gradle-enterprise-test-distribution-agent-1.1.2.jar.asc gradle-enterprise-test-distribution-agent-1.1.2.jar

The output of the last command should look similar to the following:

gpg: Signature made Tue May  5 08:36:01 2020 UTC
gpg:                using RSA key 5208812E1E4A6DB0
gpg: Good signature from "Gradle Inc. <info@gradle.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 314F E82E 5A4C 5377 BCA2  EDEC 5208 812E 1E4A 6DB0

This verifies that the artifact was signed with the private key that corresponds to the imported public key. The warning is emitted because you haven’t explicitly trusted the imported key (hence [unknown]). One way of establishing trust is to verify the fingerprint over a secure channel. Please contact technical support should you wish to do so.