# Redis SDK topology evidence. # # The lanes in infra/redis-sdk answer what the deterministic in-memory gateway cannot — Sentinel # promotion behaviour, Cluster redirects, ACL coverage. docs/redis/support-matrix.md records which # lane produced which evidence, and RedisSupportMatrixTest refuses an evidence claim that does not # name the test class behind it. # # Three cadences, because the cost and the question differ: # # pull_request standalone only, current supported version. The cheapest lane that can still # catch "this change cannot talk to a real Redis at all". A PR gate that starts # three topologies is a PR gate people learn to ignore. # schedule the full supported-version x topology matrix, nightly. This is where Sentinel # promotion and Cluster redirect evidence comes from. # workflow_dispatch one lane on demand, for reproducing a specific failure. # # A release candidate uses the nightly matrix run for its tag: `release-candidate` selects the full # matrix on demand so an RC does not have to wait for the next scheduled run. # # Each lane has its own endpoint. A sentinel is not a data node and a cluster node is not the whole # cluster, so the address, port, and (for Sentinel) the monitored primary's name are per-lane rather # than one hardcoded 6379 that happens to be right for standalone only. # # The Gradle task is fail-closed on its own account: an unknown mode, a missing endpoint, a lane # with no tagged test class, and a run that executed zero tests are all errors. This workflow does # not need to re-check those, but it does have to keep the evidence, which is why every run uploads # the JUnit XML together with the commit SHA, the server version and the resolved image digest. An # evidence artifact that cannot say which image produced it is not evidence. name: redis-sdk-topology on: pull_request: paths: - "src/adapter/outbound/cache-redis/**" - "infra/redis-sdk/**" - ".github/workflows/redis-sdk-topology.yml" schedule: # 02:30 UTC daily. Nightly, not hourly: the matrix starts real servers. - cron: "30 2 * * *" workflow_dispatch: inputs: topology: description: standalone, sentinel, cluster, tls, or release-candidate for the full matrix required: true default: standalone type: choice options: [standalone, sentinel, cluster, tls, release-candidate] redis_version: description: server version tag required: true default: "7.4" type: string permissions: contents: read jobs: # The matrix is computed rather than duplicated per trigger, so adding a supported version is one # edit and no trigger can silently keep testing an old set. lanes: runs-on: ubuntu-latest outputs: matrix: ${{ steps.select.outputs.matrix }} steps: - id: select run: | set -euo pipefail case "${{ github.event_name }}" in pull_request) matrix='{"include":[{"topology":"standalone","redis_version":"7.4"}]}' ;; schedule) matrix='{"include":[ {"topology":"standalone","redis_version":"7.2"}, {"topology":"standalone","redis_version":"7.4"}, {"topology":"standalone","redis_version":"8.2"}, {"topology":"sentinel","redis_version":"7.2"}, {"topology":"sentinel","redis_version":"7.4"}, {"topology":"sentinel","redis_version":"8.2"}, {"topology":"cluster","redis_version":"7.2"}, {"topology":"cluster","redis_version":"7.4"}, {"topology":"cluster","redis_version":"8.2"}, {"topology":"tls","redis_version":"7.4"}, {"topology":"tls","redis_version":"8.2"}]}' ;; *) if [ "${{ inputs.topology }}" = "release-candidate" ]; then matrix='{"include":[ {"topology":"standalone","redis_version":"7.2"}, {"topology":"standalone","redis_version":"7.4"}, {"topology":"standalone","redis_version":"8.2"}, {"topology":"sentinel","redis_version":"7.2"}, {"topology":"sentinel","redis_version":"7.4"}, {"topology":"sentinel","redis_version":"8.2"}, {"topology":"cluster","redis_version":"7.2"}, {"topology":"cluster","redis_version":"7.4"}, {"topology":"cluster","redis_version":"8.2"}, {"topology":"tls","redis_version":"7.4"}, {"topology":"tls","redis_version":"8.2"}]}' else matrix='{"include":[{"topology":"${{ inputs.topology }}","redis_version":"${{ inputs.redis_version }}"}]}' fi ;; esac printf 'matrix=%s\n' "$(printf '%s' "$matrix" | tr -d '\n ')" >> "$GITHUB_OUTPUT" topology-evidence: needs: lanes runs-on: ubuntu-latest timeout-minutes: 30 strategy: fail-fast: false matrix: ${{ fromJson(needs.lanes.outputs.matrix) }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2 - name: Validate Gradle wrapper id: gradle-wrapper-validation uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1 with: distribution: temurin java-version: "21.0.11+10" cache: gradle cache-dependency-path: | src/**/*.gradle src/**/gradle-wrapper.properties src/**/gradle.lockfile - name: Start the topology env: REDIS_VERSION: ${{ matrix.redis_version }} run: docker compose -f "infra/redis-sdk/${{ matrix.topology }}/compose.yml" up -d --wait - name: Record the image digest id: image run: | set -euo pipefail # The tag says 7.4; the digest says which 7.4. Evidence that names only the tag cannot be # reproduced once the tag moves. digest="$(docker image inspect --format '{{index .RepoDigests 0}}' \ "redis:${{ matrix.redis_version }}" 2>/dev/null || echo 'unresolved')" printf 'digest=%s\n' "$digest" >> "$GITHUB_OUTPUT" - name: Run the topology contracts working-directory: src run: | set -euo pipefail case '${{ matrix.topology }}' in standalone) port=6379; extra='' ;; sentinel) port=27010; extra='-Predis.topology.master=skeleton' ;; cluster) port=7100; extra='' ;; # The TLS lane's CA is generated at start-up, so the trust material is extracted from # the lane rather than checked in. A checked-in key is a secret in the repository # however loudly the file is named "test". tls) port=6390 docker compose -f ../infra/redis-sdk/tls/compose.yml cp redis:/tls/ca.crt "$RUNNER_TEMP/redis-lane-ca.pem" extra="-Predis.topology.trust-material=$RUNNER_TEMP/redis-lane-ca.pem" ;; *) echo "unknown topology"; exit 1 ;; esac ./gradlew :adapter:outbound:cache-redis:redisTopologyTest --console=plain \ -Predis.topology.host=localhost \ -Predis.topology.port="$port" \ -Predis.topology.mode='${{ matrix.topology }}' \ $extra - name: Write the evidence manifest if: always() run: | set -euo pipefail out=src/adapter/outbound/cache-redis/build/test-results/redisTopologyTest mkdir -p "$out" cat > "$out/evidence-manifest.txt" <