diff --git a/.github/actions/install-server/action.yml b/.github/actions/install-server/action.yml index afb3d845..3e3fea1c 100644 --- a/.github/actions/install-server/action.yml +++ b/.github/actions/install-server/action.yml @@ -2,12 +2,6 @@ name: Install Server description: "Build and install Valkey server binaries." inputs: - os: - description: "The current operating system (see 'os-matrix.json')" - required: true - target: - description: "Specified target for rust toolchain (see 'os-matrix.json')" - required: true server-version: description: "Server version to install (see 'server-matrix.json')" required: true @@ -18,16 +12,13 @@ runs: - name: Set environment variables shell: bash env: - OS: ${{ inputs.os }} SERVER_VERSION: ${{ inputs.server-version }} - run: | - echo "OS=$OS" >> $GITHUB_ENV - echo "SERVER_VERSION=$SERVER_VERSION" >> $GITHUB_ENV + run: echo "SERVER_VERSION=$SERVER_VERSION" >> $GITHUB_ENV # Environment variables must be passed into WSL explicitly using the WSLENV environment variable. # The '/p' flag translates the $GITHUB_ENV path from Windows to WSL format. - name: Pass environment variables to WSL - if: ${{ inputs.os == 'windows' }} + if: ${{ runner.os == 'Windows' }} shell: bash run: | echo "WSLENV=SERVER_VERSION:GITHUB_ENV/p" >> $GITHUB_ENV @@ -48,16 +39,16 @@ runs: - name: Cache compiled Valkey binaries id: cache-valkey - uses: actions/cache@v4 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: | valkey/src/valkey-cli valkey/src/valkey-server - key: valkey-${{ env.SOURCE_VERSION }}-${{ inputs.target }} + key: valkey-${{ env.SOURCE_VERSION }}-${{ runner.os }}-${{ runner.arch }} - name: Build and install Valkey binaries from source if: ${{ steps.cache-valkey.outputs.cache-hit != 'true' }} - shell: ${{ inputs.os == 'windows' && 'wsl-bash {0}' || 'bash' }} + shell: ${{ runner.os == 'Windows' && 'wsl-bash {0}' || 'bash' }} run: | git clone --depth 1 --branch "$SERVER_VERSION" --single-branch 'https://github.com/valkey-io/valkey.git' @@ -66,12 +57,12 @@ runs: - name: Install Valkey binaries from cache if: ${{ steps.cache-valkey.outputs.cache-hit == 'true' }} - shell: ${{ inputs.os == 'windows' && 'wsl-bash {0}' || 'bash' }} + shell: ${{ runner.os == 'Windows' && 'wsl-bash {0}' || 'bash' }} run: | sudo cp valkey/src/valkey-cli valkey/src/valkey-server /usr/local/bin - name: Verify Valkey installation - shell: ${{ inputs.os == 'windows' && 'wsl-bash {0}' || 'bash' }} + shell: ${{ runner.os == 'Windows' && 'wsl-bash {0}' || 'bash' }} run: | if [ ! -f /usr/local/bin/valkey-cli ] || [ ! -f /usr/local/bin/valkey-server ]; then echo "Error: Valkey installation failed." diff --git a/.github/actions/install-shared-dependencies/action.yml b/.github/actions/install-shared-dependencies/action.yml index 1e8f085f..6d272780 100644 --- a/.github/actions/install-shared-dependencies/action.yml +++ b/.github/actions/install-shared-dependencies/action.yml @@ -38,12 +38,11 @@ runs: yum install -y gcc pkgconfig openssl openssl-devel which curl gettext libasan tar --allowerasing # In Windows runners, the Valkey servers run within WSL. - # These can be accessed via the WSL bash shell. - # See for more details. - # WSL2 is not available on windows-11-arm runners (no Hyper-V), so skip for aarch64. + # - Use WSL bash shell – see . + # - WSL is not available on Windows ARM runners – see #383. - name: Install software dependencies for Windows - if: "${{ inputs.os == 'windows' && !contains(inputs.target, 'aarch64') }}" - uses: Vampire/setup-wsl@v7 + if: "${{ runner.os == 'Windows' && runner.arch != 'ARM64' }}" + uses: Vampire/setup-wsl@d1da7f2c0322a5ee4f24975344f67fc0f5baf364 # v7.0.0 with: distribution: Ubuntu-22.04 additional-packages: python3 build-essential git pkg-config libssl-dev @@ -55,12 +54,11 @@ runs: # Always build from source first. This installs 'valkey-cli', which is # needed by 'start-valkey-docker' to start servers in Docker. + # Valkey servers cannot be installed on Windows ARM runners - see #383. - name: Install server from source - if: "${{ inputs.server-version }}" + if: "${{ inputs.server-version && !(runner.os == 'Windows' && runner.arch == 'ARM64') }}" uses: ./.github/actions/install-server with: - os: ${{ inputs.os }} - target: ${{ inputs.target }} server-version: ${{ inputs.server-version }} # For valkey 9.0 on ubuntu, also start Docker containers with the diff --git a/.github/actions/run-coverage/action.yml b/.github/actions/run-coverage/action.yml index 0e2b888e..a0a05134 100644 --- a/.github/actions/run-coverage/action.yml +++ b/.github/actions/run-coverage/action.yml @@ -41,13 +41,13 @@ runs: fi - name: Upload coverage report artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: coverage-report path: reports/ - name: Upload coverage results artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: test-results path: testresults/ diff --git a/.github/json_matrices/load_matrices.py b/.github/json_matrices/load_matrices.py index 088dde56..c4ab1700 100755 --- a/.github/json_matrices/load_matrices.py +++ b/.github/json_matrices/load_matrices.py @@ -31,12 +31,12 @@ def main() -> None: profile = sys.argv[1] os_matrix = filter_by_profile(load_json("os-matrix.json"), profile) - host = [h for h in os_matrix if "IMAGE" not in h] - container_host = [h for h in os_matrix if "IMAGE" in h] + host = [h for h in os_matrix if "image" not in h] + container_host = [h for h in os_matrix if "image" in h] server = filter_by_profile(load_json("server-matrix.json"), profile) assert server, "Given profile resulted in empty server matrix." - + dotnet_entries = filter_by_profile(load_json("version-matrix.json"), profile) dotnet = [e["version"] for e in dotnet_entries] assert dotnet, "Given profile resulted in empty dotnet version matrix." @@ -54,7 +54,7 @@ def main() -> None: if github_output: with open(github_output, "a") as f: for key, value in configs.items(): - print(f"{key}={value}", file=f) + print(f"{key}={value}", file=f) else: for key, value in configs.items(): print(f"{key}={value}") diff --git a/.github/json_matrices/os-matrix.json b/.github/json_matrices/os-matrix.json index d7438e7b..cf53713a 100644 --- a/.github/json_matrices/os-matrix.json +++ b/.github/json_matrices/os-matrix.json @@ -1,53 +1,45 @@ [ { - "OS": "ubuntu", - "RUNNER": "ubuntu-24.04", - "ARCH": "x64", - "TARGET": "x86_64-unknown-linux-gnu", + "os": "ubuntu", + "runner": "ubuntu-24.04", + "target": "x86_64-unknown-linux-gnu", "profiles": [ "standard", "full"] }, { - "OS": "ubuntu", - "RUNNER": "ubuntu-24.04-arm", - "ARCH": "arm64", - "TARGET": "aarch64-unknown-linux-gnu", + "os": "ubuntu", + "runner": "ubuntu-24.04-arm", + "target": "aarch64-unknown-linux-gnu", "profiles": [ "full"] }, { - "OS": "amazon-linux", - "RUNNER": "ubuntu-latest", - "ARCH": "x64", - "TARGET": "x86_64-unknown-linux-gnu", - "IMAGE": "amazonlinux:latest", + "os": "amazon-linux", + "runner": "ubuntu-latest", + "target": "x86_64-unknown-linux-gnu", + "image": "amazonlinux:latest", "profiles": ["full"] }, { - "OS": "macos", - "RUNNER": "macos-15", - "ARCH": "arm64", - "TARGET": "aarch64-apple-darwin", + "os": "macos", + "runner": "macos-15", + "target": "aarch64-apple-darwin", "profiles": [ "full"] }, { - "OS": "macos", - "NAMED_OS": "darwin", - "RUNNER": "macos-15-intel", - "ARCH": "x64", - "TARGET": "x86_64-apple-darwin", + "os": "macos", + "runner": "macos-15-intel", + "target": "x86_64-apple-darwin", "profiles": [ "full"] }, { - "OS": "windows", - "RUNNER": "windows-2025", - "ARCH": "x64", - "TARGET": "x86_64-pc-windows-msvc", + "os": "windows", + "runner": "windows-2025", + "target": "x86_64-pc-windows-msvc", "profiles": [ "standard", "full"] }, { - "OS": "windows", - "RUNNER": "windows-11-arm", - "ARCH": "arm64", - "TARGET": "aarch64-pc-windows-msvc", - "profiles": [] + "os": "windows", + "runner": "windows-11-arm", + "target": "aarch64-pc-windows-msvc", + "profiles": ["full"] } ] diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 9b71f949..916a06f6 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -43,7 +43,7 @@ jobs: working-directory: .github/json_matrices # Select all VM runners (non-container) — each produces a unique native binary for the NuGet package. run: | - PLATFORM_MATRIX=$(jq -c '[.[] | select(has("IMAGE") | not)]' < os-matrix.json) + PLATFORM_MATRIX=$(jq -c '[.[] | select(has("image") | not)]' < os-matrix.json) echo "PLATFORM_MATRIX=$PLATFORM_MATRIX" | tee -a "$GITHUB_OUTPUT" set-release-version: @@ -78,7 +78,7 @@ jobs: fail-fast: false matrix: host: ${{ fromJson(needs.load-platform-matrix.outputs.PLATFORM_MATRIX) }} - runs-on: ${{ matrix.host.RUNNER }} + runs-on: ${{ matrix.host.runner }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -94,36 +94,36 @@ jobs: - name: Install shared software dependencies uses: ./.github/actions/install-shared-dependencies with: - os: ${{ matrix.host.OS }} - target: ${{ matrix.host.TARGET }} + os: ${{ matrix.host.os }} + target: ${{ matrix.host.target }} - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: rust/target - key: rust-${{ matrix.host.TARGET }} + key: rust-${{ matrix.host.target }} - name: Build native libs (linux gnu) - if: ${{ contains(matrix.host.TARGET, 'linux-gnu') }} + if: ${{ contains(matrix.host.target, 'linux-gnu') }} working-directory: rust run: | - cargo zigbuild -r --target ${{ matrix.host.TARGET }}.2.17 + cargo zigbuild -r --target ${{ matrix.host.target }}.2.17 mkdir -p target/release - name: Build native libs - if: ${{ !contains(matrix.host.TARGET, 'linux-gnu') }} + if: ${{ !contains(matrix.host.target, 'linux-gnu') }} working-directory: rust - run: cargo build --release --target ${{ matrix.host.TARGET }} + run: cargo build --release --target ${{ matrix.host.target }} - name: Upload artifacts to publish continue-on-error: true uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: ${{ matrix.host.TARGET }} + name: ${{ matrix.host.target }} if-no-files-found: error path: | - rust/target/${{ matrix.host.TARGET }}/release/*.so - rust/target/${{ matrix.host.TARGET }}/release/*.dylib - rust/target/${{ matrix.host.TARGET }}/release/*.dll + rust/target/${{ matrix.host.target }}/release/*.so + rust/target/${{ matrix.host.target }}/release/*.dylib + rust/target/${{ matrix.host.target }}/release/*.dll build-package-to-publish: needs: [set-release-version, create-binaries] diff --git a/.github/workflows/report-failures.yml b/.github/workflows/report-failures.yml deleted file mode 100644 index b8d8da2a..00000000 --- a/.github/workflows/report-failures.yml +++ /dev/null @@ -1,207 +0,0 @@ -name: C# failure reporter - -on: - workflow_run: - workflows: ["C# tests"] - types: [completed] - branches: [jbrinkman/matrix-errors] - -permissions: - actions: read - contents: read - issues: write - -jobs: - report: - # Only run this job when the triggering run failed and was schedule or workflow_dispatch - if: ${{ github.event.workflow_run.conclusion == 'failure' && (github.event.workflow_run.event == 'schedule' || github.event.workflow_run.event == 'workflow_dispatch') }} - runs-on: ubuntu-latest - steps: - - name: Download inputs.json artifact (if present) - id: inputs - uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21 - continue-on-error: true - with: - run_id: ${{ github.event.workflow_run.id }} - name: inputs.json - path: inputs_artifact - - - name: Gate on full-matrix runs - id: gate - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ github.token }} - script: | - const {owner, repo} = context.repo; - const runId = context.payload.workflow_run.id; - const event = context.payload.workflow_run.event; - const { data: run } = await github.rest.actions.getWorkflowRun({ owner, repo, run_id: runId }); - const title = run.display_title || run.name || ''; - // Prefer inputs.json when workflow_dispatch - let should = false; - if (event === 'schedule') { - should = true; - } else if (event === 'workflow_dispatch') { - try { - const fs = require('fs'); - const path = 'inputs_artifact/inputs.json'; - if (fs.existsSync(path)) { - const data = JSON.parse(fs.readFileSync(path, 'utf8')); - const fm = !!(data.inputs && data.inputs['full-matrix']); - should = fm; - core.info(`Gate via inputs.json: full-matrix=${fm}`); - } else { - core.info('inputs.json not found; falling back to title gate'); - should = title.startsWith('C# Matrix Tests'); - } - } catch (e) { - core.warning(`Failed to read inputs.json: ${e}`); - should = title.startsWith('C# Matrix Tests'); - } - } - core.info(`Trigger event: ${event}; run title: ${title}; should process: ${should}`); - return should; - - - name: Download artifacts from triggering run - uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21 - if: ${{ steps.gate.outputs.result == 'true' }} - with: - run_id: ${{ github.event.workflow_run.id }} - path: downloaded - - - name: Aggregate failures - id: aggregate - shell: bash - if: ${{ steps.gate.outputs.result == 'true' }} - run: | - set -euo pipefail - sudo apt-get update -y >/dev/null 2>&1 || true - sudo apt-get install -y jq xmlstarlet >/dev/null 2>&1 || true - shopt -s nullglob - - total_failed=0 - total_legs=0 - failing_legs=0 - md="\n" - md+="# Nightly CI failures for ${{ github.repository }}\n" - md+="Triggered: ${{ github.event.workflow_run.run_started_at }} • [Run link](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }})\n\n" - md_details="" - - # Iterate each artifact folder downloaded - for dir in downloaded/*; do - [ -d "$dir" ] || continue - base="$(basename "$dir")" - case "$base" in - test-reports-*) ;; - *) continue ;; - esac - total_legs=$((total_legs+1)) - job_display="$base" - - # Prefer failures.json - fjson="$dir/failures.json" - failed=0; total=0 - if [ -f "$fjson" ]; then - failed=$(jq -r '.summary.failed // 0' "$fjson" 2>/dev/null || echo 0) - total=$(jq -r '.summary.total // 0' "$fjson" 2>/dev/null || echo 0) - fi - - # Fallback to TRX parse if counts are zero - if [ "$failed" = "0" ] && [ "$total" = "0" ]; then - trx=$(find "$dir" -maxdepth 1 -name '*.trx' -print -quit 2>/dev/null || true) - if [ -n "$trx" ]; then - total=$(xmlstarlet sel -T -t -v 'string(//*[local-name()="Counters"]/@total)' "$trx" 2>/dev/null || echo 0) - failed=$(xmlstarlet sel -T -t -v 'string(//*[local-name()="Counters"]/@failed)' "$trx" 2>/dev/null || echo 0) - fi - fi - - # Emit only failing legs with per-test bullets - if [ "$failed" != "0" ]; then - failing_legs=$((failing_legs+1)) - total_failed=$((total_failed+failed)) - md+="- ${job_display}: ${failed}/${total} failed\n" - # Try to get failed tests either from failures.json or directly from TRX - bullets="" - if [ -f "$fjson" ]; then - bullets=$(jq -r '.failed[]? | " - " + (.displayName // .fullyQualifiedName // .name // "(unknown)") + (if .errorMessage then " — " + .errorMessage else (if .message then " — " + .message else "" end) end)' "$fjson" 2>/dev/null || true) - fi - if [ -z "$bullets" ]; then - if [ -n "${trx:-}" ] && [ -f "$trx" ]; then - while IFS= read -r line; do - name="${line%%||*}" - msg="${line#*||}" - # Trim to first line and limit length - msg="${msg%%$'\n'*}" - if [ ${#msg} -gt 200 ]; then msg="${msg:0:197}..."; fi - echo " - ${name} — ${msg}" - done < <(xmlstarlet sel -T -t -m '//*[local-name()="UnitTestResult" and @outcome="Failed"]' -v 'concat(@testName,"||", normalize-space(.//*[local-name()="Message"]))' -n "$trx" 2>/dev/null || true) > "$dir/.bullets.txt" - bullets=$(cat "$dir/.bullets.txt" 2>/dev/null || true) - fi - fi - if [ -n "$bullets" ]; then - md_details+=$'\n' - md_details+="### ${job_display}\n\n" - md_details+="$bullets\n" - fi - fi - done - - if [ "$failing_legs" = "0" ]; then - md+="The pipeline failed, but no individual test failures were found. This may indicate a job or infrastructure failure.\n" - fi - md+=$'\n' - md+="Total failed tests across ${failing_legs} of ${total_legs} matrix jobs: ${total_failed}\n\n" - md+="$md_details" - - printf "%b" "$md" > summary.md - { - echo "summary_path=$(pwd)/summary.md" - echo "total_failed=${total_failed}" - echo "total_legs=${total_legs}" - } >> "$GITHUB_OUTPUT" - - - name: Find or create rolling failure issue - id: ensure_issue - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - if: ${{ steps.gate.outputs.result == 'true' }} - env: - SUMMARY_PATH: ${{ steps.aggregate.outputs.summary_path }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const fs = require('fs'); - const body = fs.readFileSync(process.env.SUMMARY_PATH, 'utf8'); - const marker = ''; - const {owner, repo} = context.repo; - const label = 'ci-failure'; - const title = 'Nightly CI failures: C# tests'; - - // Ensure label exists? Assume it's created manually as per repo policy. - const {data: issues} = await github.rest.issues.listForRepo({ - owner, repo, state: 'open', labels: label, per_page: 100 - }); - let issue = issues.find(i => i.title === title); - - if (!issue) { - const created = await github.rest.issues.create({ - owner, repo, title, body, labels: [label] - }); - core.setOutput('issue_number', String(created.data.number)); - core.info(`Created issue #${created.data.number}`); - return; - } - - // Avoid duplicate comments for the same run using marker - const {data: comments} = await github.rest.issues.listComments({ - owner, repo, issue_number: issue.number, per_page: 100 - }); - const exists = comments.some(c => c.body && c.body.includes(marker)); - if (!exists) { - await github.rest.issues.createComment({ - owner, repo, issue_number: issue.number, body - }); - core.info(`Commented on issue #${issue.number}`); - } else { - core.info('A comment for this run already exists; skipping.'); - } - core.setOutput('issue_number', String(issue.number)); diff --git a/.github/workflows/scripts/create_failures_json.sh b/.github/workflows/scripts/create_failures_json.sh deleted file mode 100755 index c44f187f..00000000 --- a/.github/workflows/scripts/create_failures_json.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash -# Derive failures.json from a TRX test results file. -# -# Required environment variables: -# TRX_FILE, JOB_NAME, DOTNET, SERVER_TYPE, SERVER_VERSION, -# HOST_OS, HOST_ARCH, HOST_RUNNER, RUN_ID, RUN_URL -set -euo pipefail - -SUMMARY_FILE=failures.json - -if ! command -v xmllint >/dev/null 2>&1 || ! command -v jq >/dev/null 2>&1; then - echo '{"workflow":"C# tests","summary":{"note":"Install xmllint+jq for rich failures"}}' > "$SUMMARY_FILE" - exit 0 -fi - -FAILED_COUNT=$(xmllint --xpath "string(//*[local-name()='Counters']/@failed)" "$TRX_FILE" 2>/dev/null || echo 0) -PASSED_COUNT=$(xmllint --xpath "string(//*[local-name()='Counters']/@passed)" "$TRX_FILE" 2>/dev/null || echo 0) -TOTAL_COUNT=$(xmllint --xpath "string(//*[local-name()='Counters']/@total)" "$TRX_FILE" 2>/dev/null || echo 0) -SKIPPED_COUNT=$(xmllint --xpath "string(//*[local-name()='Counters']/@skipped)" "$TRX_FILE" 2>/dev/null || echo 0) - -# xmllint returns empty string (exit 0) when the XPath matches nothing; coerce to 0 for --argjson. -FAILED_COUNT=${FAILED_COUNT:-0} -PASSED_COUNT=${PASSED_COUNT:-0} -TOTAL_COUNT=${TOTAL_COUNT:-0} -SKIPPED_COUNT=${SKIPPED_COUNT:-0} - -jq -n \ - --arg workflow "C# tests" \ - --argjson runId "$RUN_ID" \ - --arg jobName "$JOB_NAME" \ - --arg dotnet "$DOTNET" \ - --arg serverType "$SERVER_TYPE" \ - --arg serverVersion "$SERVER_VERSION" \ - --arg os "$HOST_OS" \ - --arg arch "$HOST_ARCH" \ - --arg runner "$HOST_RUNNER" \ - --argjson total "$TOTAL_COUNT" \ - --argjson passed "$PASSED_COUNT" \ - --argjson failed "$FAILED_COUNT" \ - --argjson skipped "$SKIPPED_COUNT" \ - --arg runUrl "$RUN_URL" \ - '{ - workflow: $workflow, - runId: $runId, - jobName: $jobName, - matrix: { - dotnet: $dotnet, - server: { type: $serverType, version: $serverVersion }, - host: { OS: $os, ARCH: $arch, RUNNER: $runner } - }, - summary: { total: $total, passed: $passed, failed: $failed, skipped: $skipped }, - failed: [], - links: { runUrl: $runUrl } - }' > "$SUMMARY_FILE" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 37586592..7abf7f89 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,7 +59,7 @@ jobs: run: python3 load_matrices.py "$PROFILE" test-with-runners: - name: net${{ matrix.dotnet }}, ${{ matrix.server.type }} ${{ matrix.server.version }}, ${{ matrix.host.TARGET }} + name: net${{ matrix.dotnet }}, ${{ matrix.server.type }} ${{ matrix.server.version }}, ${{ matrix.host.target }} needs: load-matrix timeout-minutes: 100 strategy: @@ -68,7 +68,7 @@ jobs: dotnet: ${{ fromJson(needs.load-matrix.outputs.dotnet-matrix) }} server: ${{ fromJson(needs.load-matrix.outputs.server-matrix) }} host: ${{ fromJson(needs.load-matrix.outputs.host-matrix) }} - runs-on: ${{ matrix.host.RUNNER }} + runs-on: ${{ matrix.host.runner }} env: VALKEY_GLIDE_DNS_TESTS_ENABLED: "1" @@ -127,73 +127,70 @@ jobs: - name: Install shared software dependencies uses: ./.github/actions/install-shared-dependencies with: - os: ${{ matrix.host.OS }} - target: ${{ matrix.host.TARGET }} + os: ${{ matrix.host.os }} + target: ${{ matrix.host.target }} server-version: ${{ matrix.server.version }} - - name: Configure DNS for tests + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + if: ${{ inputs.package-version == '' }} + with: + path: rust/target + key: rust-${{ matrix.host.target }} + + - name: Unit tests - dotnet ${{ matrix.dotnet }} + run: >- + dotnet test tests/Valkey.Glide.UnitTests/ + --configuration Debug + --framework net${{ matrix.dotnet }} + --logger "html;LogFileName=UnitTestReport.html" + --logger "trx;LogFileName=UnitTestResults.trx" + --logger "console;verbosity=detailed" + --results-directory . + + - name: Configure DNS for integration tests + if: ${{ matrix.host.target != 'aarch64-pc-windows-msvc' }} shell: bash run: | ENTRIES="127.0.0.1 valkey.glide.test.tls.com 127.0.0.1 valkey.glide.test.no_tls.com ::1 valkey.glide.test.tls.com ::1 valkey.glide.test.no_tls.com" - if [[ "${{ matrix.host.OS }}" == "windows" ]]; then + if [[ "${{ runner.os }}" == "Windows" ]]; then echo "$ENTRIES" >> /c/Windows/System32/drivers/etc/hosts else echo "$ENTRIES" | sudo tee -a /etc/hosts fi - - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 - if: ${{ inputs.package-version == '' }} - with: - path: rust/target - key: rust-${{ matrix.host.TARGET }} - - - name: Test dotnet ${{ matrix.dotnet }} + - name: Integration tests - dotnet ${{ matrix.dotnet }} + if: ${{ matrix.host.target != 'aarch64-pc-windows-msvc' }} env: AWS_ACCESS_KEY_ID: test_secret_key AWS_SECRET_ACCESS_KEY: test_access_key AWS_SESSION_TOKEN: test_session_token run: >- - dotnet test + dotnet test tests/Valkey.Glide.IntegrationTests/ --configuration Debug --framework net${{ matrix.dotnet }} - --logger "html;LogFileName=TestReport.html" - --logger "trx;LogFileName=TestResults.trx" + --logger "html;LogFileName=IntegrationTestReport.html" + --logger "trx;LogFileName=IntegrationTestResults.trx" --logger "console;verbosity=detailed" --results-directory . - - name: Create failures.json from TRX - if: always() - shell: bash - env: - TRX_FILE: TestResults.trx - JOB_NAME: "net${{ matrix.dotnet }}, server ${{ matrix.server.version }}, ${{ matrix.host.TARGET }}" - DOTNET: ${{ matrix.dotnet }} - SERVER_TYPE: ${{ matrix.server.type }} - SERVER_VERSION: ${{ matrix.server.version }} - HOST_OS: ${{ matrix.host.OS }} - HOST_ARCH: ${{ matrix.host.ARCH }} - HOST_RUNNER: ${{ matrix.host.RUNNER }} - RUN_ID: ${{ github.run_id }} - RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - run: .github/workflows/scripts/create_failures_json.sh - - name: Upload test reports if: always() continue-on-error: true uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: test-reports-dotnet-${{ matrix.dotnet }}-${{ matrix.server.type }}-${{ matrix.server.version }}-${{ matrix.host.OS }}-${{ matrix.host.ARCH }} + name: test-reports-dotnet-${{ matrix.dotnet }}-${{ matrix.server.type }}-${{ matrix.server.version }}-${{ matrix.host.os }}-${{ runner.arch }} path: | - TestReport.html - TestResults.trx - failures.json + UnitTestReport.html + UnitTestResults.trx + IntegrationTestReport.html + IntegrationTestResults.trx valkey-glide/utils/clusters/** test-with-containers: - name: net${{ matrix.dotnet }}, ${{ matrix.server.type }} ${{ matrix.server.version }}, ${{ matrix.host.IMAGE }} + name: net${{ matrix.dotnet }}, ${{ matrix.server.type }} ${{ matrix.server.version }}, ${{ matrix.host.image }} needs: load-matrix if: ${{ needs.load-matrix.outputs.container-host-matrix != '[]' }} timeout-minutes: 100 @@ -203,9 +200,9 @@ jobs: dotnet: ${{ fromJson(needs.load-matrix.outputs.dotnet-matrix) }} server: ${{ fromJson(needs.load-matrix.outputs.server-matrix) }} host: ${{ fromJson(needs.load-matrix.outputs.container-host-matrix) }} - runs-on: ${{ matrix.host.RUNNER }} + runs-on: ${{ matrix.host.runner }} container: - image: ${{ matrix.host.IMAGE }} + image: ${{ matrix.host.image }} env: VALKEY_GLIDE_DNS_TESTS_ENABLED: "1" @@ -240,8 +237,8 @@ jobs: - name: Install shared software dependencies uses: ./.github/actions/install-shared-dependencies with: - os: ${{ matrix.host.OS }} - target: ${{ matrix.host.TARGET }} + os: ${{ matrix.host.os }} + target: ${{ matrix.host.target }} server-version: ${{ matrix.server.version }} - name: Configure DNS for tests @@ -256,7 +253,7 @@ jobs: - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: rust/target - key: rust-${{ matrix.host.IMAGE }} + key: rust-${{ matrix.host.image }} - name: Test dotnet ${{ matrix.dotnet }} run: >- @@ -267,32 +264,15 @@ jobs: --logger "console;verbosity=detailed" --results-directory . - - name: Create failures.json from TRX - if: always() - shell: bash - env: - TRX_FILE: TestResults.trx - JOB_NAME: "net${{ matrix.dotnet }}, server ${{ matrix.server.version }}, ${{ matrix.host.TARGET }}" - DOTNET: ${{ matrix.dotnet }} - SERVER_TYPE: ${{ matrix.server.type }} - SERVER_VERSION: ${{ matrix.server.version }} - HOST_OS: ${{ matrix.host.OS }} - HOST_ARCH: ${{ matrix.host.ARCH }} - HOST_RUNNER: ${{ matrix.host.RUNNER }} - RUN_ID: ${{ github.run_id }} - RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - run: .github/workflows/scripts/create_failures_json.sh - - name: Upload test reports if: always() continue-on-error: true uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: test-reports-dotnet-${{ matrix.dotnet }}-${{ matrix.server.type }}-${{ matrix.server.version }}-${{ matrix.host.IMAGE }}-${{ matrix.host.ARCH }} + name: test-reports-dotnet-${{ matrix.dotnet }}-${{ matrix.server.type }}-${{ matrix.server.version }}-${{ matrix.host.image }}-${{ runner.arch }} path: | TestReport.html TestResults.trx - failures.json valkey-glide/utils/clusters/** # See: https://github.com/valkey-io/valkey-glide-csharp/issues/390 @@ -341,22 +321,6 @@ jobs: --logger "console;verbosity=detailed" --results-directory . - - name: Create failures.json from TRX - if: always() - shell: bash - env: - TRX_FILE: ModuleTestResults.trx - JOB_NAME: "Module tests (Docker, net${{ matrix.dotnet }})" - DOTNET: ${{ matrix.dotnet }} - SERVER_TYPE: valkey - SERVER_VERSION: "9.0" - HOST_OS: ubuntu - HOST_ARCH: x64 - HOST_RUNNER: ubuntu-24.04 - RUN_ID: ${{ github.run_id }} - RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - run: .github/workflows/scripts/create_failures_json.sh - - name: Upload test reports if: always() continue-on-error: true @@ -366,4 +330,3 @@ jobs: path: | ModuleTestReport.html ModuleTestResults.trx - failures.json diff --git a/docs/ci-cd.md b/docs/ci-cd.md index f71d6dd9..df95b854 100644 --- a/docs/ci-cd.md +++ b/docs/ci-cd.md @@ -1,36 +1,38 @@ # CI/CD Test Matrices -This directory contains our CI/CD configurations. Our test runs are based on profiles, where each profile define -a set of platforms, versions, and tests to be run. The json files list our available configurations and options. -`load_matrices.py` is used to process the profile and load the appropriate configs onto Github workflow environments. +The `.github/json_matrices/` directory contains our CI/CD matrix configurations. Our test runs are based on profiles, +where each profile defines a set of platforms, versions, and tests to be run. The JSON files list our available +configurations and options. `load_matrices.py` is used to process the profile and load the appropriate configs onto +GitHub workflow environments. ## Files -| File | Purpose | -| ---- | ------- | -| `os-matrix.json` | OS/runner platforms (VMs and containers) | -| `server-matrix.json` | Valkey and Redis server versions | -| `version-matrix.json` | .NET SDK versions | -| `profiles.json` | Profiles and their settings (e.g., test filters) | -| `load_matrices.py` | Filters all matrices by profile, outputs to `$GITHUB_OUTPUT` | +| File | Purpose | +| --------------------- | ------------------------------------------------------------ | +| `os-matrix.json` | OS/runner platforms (VMs and containers) | +| `server-matrix.json` | Valkey and Redis server versions | +| `version-matrix.json` | .NET SDK versions | +| `profiles.json` | Profiles and their settings (e.g., test filters) | +| `load_matrices.py` | Filters all matrices by profile, outputs to `$GITHUB_OUTPUT` | ## Profiles Each entry in the JSON files has a `profiles` array that declares which test profiles include it: -| Profile | When used | -| ---------- | -------------------------------------------------------------------------- | -| `standard` | Standard tests run on common platform | -| `full` | Nightly / manual run on all platforms and all tests | +| Profile | When used | +| ---------- | --------------------------------------------------- | +| `standard` | Standard tests run on common platform | +| `full` | Nightly / manual run on all platforms and all tests | ### Example ```json { - "OS": "ubuntu", - "RUNNER": "ubuntu-24.04", + "os": "ubuntu", + "runner": "ubuntu-24.04", + "target": "x86_64-unknown-linux-gnu", "profiles": [ "standard", "full"] } ``` -This host runs in all three profiles. A host with `"profiles": ["full"]` only runs in the full suite. +This host runs in both profiles. A host with `"profiles": ["full"]` only runs in the full suite. diff --git a/tests/Valkey.Glide.IntegrationTests/FlushDatabaseTests.cs b/tests/Valkey.Glide.IntegrationTests/FlushDatabaseTests.cs index 6b3d71af..4385c394 100644 --- a/tests/Valkey.Glide.IntegrationTests/FlushDatabaseTests.cs +++ b/tests/Valkey.Glide.IntegrationTests/FlushDatabaseTests.cs @@ -54,7 +54,7 @@ public async Task FlushDatabaseAsync_Cluster_ClearsDatabase() Assert.True(await client.ExistsAsync(key)); Assert.Equal(1, await client.DatabaseSizeAsync()); - await client.FlushDatabaseAsync(); + await client.FlushDatabaseAsync(FlushMode.Sync); Assert.False(await client.ExistsAsync(key)); Assert.Equal(0, await client.DatabaseSizeAsync()); @@ -71,7 +71,7 @@ public async Task FlushDatabaseAsync_Cluster_WithRoute_ClearsDatabase() Assert.True(await client.ExistsAsync(key)); Assert.Equal(1, await client.DatabaseSizeAsync()); - await client.FlushDatabaseAsync(Route.AllPrimaries); + await client.FlushDatabaseAsync(FlushMode.Sync, Route.AllPrimaries); Assert.False(await client.ExistsAsync(key)); Assert.Equal(0, await client.DatabaseSizeAsync());