Nightly fuzz #24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Nightly fuzz | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| seed: | |
| description: Exact seed string; blank derives one from the commit and run id | |
| required: false | |
| type: string | |
| case: | |
| description: Optional single case index to replay | |
| required: false | |
| type: string | |
| cases: | |
| description: Optional per-target case-count override | |
| required: false | |
| type: string | |
| steps: | |
| description: Optional state-machine step-count override | |
| required: false | |
| type: string | |
| schedule: | |
| # Separate from the 04:17 UTC hermetic E2E campaign. | |
| - cron: '37 2 * * *' | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: fuzz-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| irc: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| shard: ${{ fromJSON(inputs.case && '[0]' || '[0,1,2]') }} | |
| env: | |
| MOTD_FUZZ_PROFILE: nightly | |
| MOTD_FUZZ_SEED: ${{ inputs.seed || format('{0}-{1}', github.sha, github.run_id) }} | |
| MOTD_FUZZ_CASE: ${{ inputs.case || '' }} | |
| MOTD_FUZZ_CASES: ${{ inputs.cases || '' }} | |
| MOTD_FUZZ_STEPS: ${{ inputs.steps || '' }} | |
| MOTD_FUZZ_SHARD: ${{ matrix.shard }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0 | |
| with: { distribution: temurin, java-version: 21 } | |
| - uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 | |
| - name: Run pure-JVM generated targets | |
| run: ./gradlew :irc:test --tests 'io.github.trevarj.motd.irc.fuzz.*' --stacktrace | |
| - name: Publish IRC fuzz summary | |
| if: always() | |
| shell: bash | |
| run: | | |
| if [[ -n "$MOTD_FUZZ_CASE" ]]; then | |
| parser_cases=1 | |
| mapper_cases=1 | |
| elif [[ -n "$MOTD_FUZZ_CASES" ]]; then | |
| parser_cases="$MOTD_FUZZ_CASES" | |
| mapper_cases="$MOTD_FUZZ_CASES" | |
| else | |
| parser_cases=200000 | |
| mapper_cases=75000 | |
| fi | |
| if [[ -n "$MOTD_FUZZ_CASE" ]]; then | |
| parser_range="$MOTD_FUZZ_CASE" | |
| mapper_range="$MOTD_FUZZ_CASE" | |
| else | |
| parser_first=$((MOTD_FUZZ_SHARD * parser_cases)) | |
| mapper_first=$((MOTD_FUZZ_SHARD * mapper_cases)) | |
| parser_range="$parser_first-$((parser_first + parser_cases - 1))" | |
| mapper_range="$mapper_first-$((mapper_first + mapper_cases - 1))" | |
| fi | |
| { | |
| echo "### IRC fuzz shard $MOTD_FUZZ_SHARD" | |
| echo "- Seed: \`$MOTD_FUZZ_SEED\`" | |
| echo "- IRC parser cases: $parser_cases (indices $parser_range)" | |
| echo "- Event mapper cases: $mapper_cases (indices $mapper_range)" | |
| echo "- Generated cases: $((parser_cases + mapper_cases)) plus checked-in regressions" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Upload IRC fuzz diagnostics | |
| if: failure() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: nightly-irc-fuzz-${{ github.run_id }}-${{ matrix.shard }} | |
| path: | | |
| irc/build/fuzz-failures/** | |
| irc/build/reports/tests/test/** | |
| if-no-files-found: ignore | |
| app: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| shard: ${{ fromJSON(inputs.case && '[0]' || '[0,1,2]') }} | |
| env: | |
| MOTD_FUZZ_PROFILE: nightly | |
| MOTD_FUZZ_SEED: ${{ inputs.seed || format('{0}-{1}', github.sha, github.run_id) }} | |
| MOTD_FUZZ_CASE: ${{ inputs.case || '' }} | |
| MOTD_FUZZ_CASES: ${{ inputs.cases || '' }} | |
| MOTD_FUZZ_STEPS: ${{ inputs.steps || '' }} | |
| MOTD_FUZZ_SHARD: ${{ matrix.shard }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0 | |
| with: { distribution: temurin, java-version: 21 } | |
| - uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 | |
| - name: Run app generated targets | |
| run: ./gradlew :app:testFossDebugUnitTest --tests 'io.github.trevarj.motd.fuzz.*' --stacktrace | |
| - name: Publish app fuzz summary | |
| if: always() | |
| shell: bash | |
| run: | | |
| if [[ -n "$MOTD_FUZZ_CASE" ]]; then | |
| presentation_cases=1 | |
| timeline_cases=1 | |
| processor_cases=1 | |
| elif [[ -n "$MOTD_FUZZ_CASES" ]]; then | |
| presentation_cases="$MOTD_FUZZ_CASES" | |
| timeline_cases="$MOTD_FUZZ_CASES" | |
| processor_cases="$MOTD_FUZZ_CASES" | |
| else | |
| presentation_cases=75000 | |
| timeline_cases=1500 | |
| processor_cases=500 | |
| fi | |
| timeline_steps="${MOTD_FUZZ_STEPS:-128}" | |
| if [[ -n "$MOTD_FUZZ_CASE" ]]; then | |
| presentation_range="$MOTD_FUZZ_CASE" | |
| timeline_range="$MOTD_FUZZ_CASE" | |
| processor_range="$MOTD_FUZZ_CASE" | |
| else | |
| presentation_first=$((MOTD_FUZZ_SHARD * presentation_cases)) | |
| timeline_first=$((MOTD_FUZZ_SHARD * timeline_cases)) | |
| processor_first=$((MOTD_FUZZ_SHARD * processor_cases)) | |
| presentation_range="$presentation_first-$((presentation_first + presentation_cases - 1))" | |
| timeline_range="$timeline_first-$((timeline_first + timeline_cases - 1))" | |
| processor_range="$processor_first-$((processor_first + processor_cases - 1))" | |
| fi | |
| { | |
| echo "### App fuzz shard $MOTD_FUZZ_SHARD" | |
| echo "- Seed: \`$MOTD_FUZZ_SEED\`" | |
| echo "- Presentation cases: $presentation_cases (indices $presentation_range)" | |
| echo "- Canonical timeline cases: $timeline_cases x $timeline_steps steps (indices $timeline_range)" | |
| echo "- EventProcessor cases: $processor_cases (indices $processor_range)" | |
| echo "- Canonical timeline operations: $((timeline_cases * timeline_steps))" | |
| echo "- Generated cases: $((presentation_cases + timeline_cases + processor_cases)) plus checked-in regressions" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Upload app fuzz diagnostics | |
| if: failure() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: nightly-app-fuzz-${{ github.run_id }}-${{ matrix.shard }} | |
| path: | | |
| app/build/fuzz-failures/** | |
| app/build/reports/tests/testFossDebugUnitTest/** | |
| if-no-files-found: ignore | |
| summary: | |
| if: always() | |
| needs: [irc, app] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Publish aggregate fuzz summary | |
| shell: bash | |
| env: | |
| REQUESTED_CASE: ${{ inputs.case || '' }} | |
| REQUESTED_CASES: ${{ inputs.cases || '' }} | |
| REQUESTED_STEPS: ${{ inputs.steps || '' }} | |
| IRC_RESULT: ${{ needs.irc.result }} | |
| APP_RESULT: ${{ needs.app.result }} | |
| run: | | |
| shards=3 | |
| if [[ -n "$REQUESTED_CASE" ]]; then | |
| shards=1 | |
| parser_cases=1 | |
| mapper_cases=1 | |
| presentation_cases=1 | |
| timeline_cases=1 | |
| processor_cases=1 | |
| elif [[ -n "$REQUESTED_CASES" ]]; then | |
| parser_cases="$REQUESTED_CASES" | |
| mapper_cases="$REQUESTED_CASES" | |
| presentation_cases="$REQUESTED_CASES" | |
| timeline_cases="$REQUESTED_CASES" | |
| processor_cases="$REQUESTED_CASES" | |
| else | |
| parser_cases=200000 | |
| mapper_cases=75000 | |
| presentation_cases=75000 | |
| timeline_cases=1500 | |
| processor_cases=500 | |
| fi | |
| timeline_steps="${REQUESTED_STEPS:-128}" | |
| generated_per_shard=$((parser_cases + mapper_cases + presentation_cases + timeline_cases + processor_cases)) | |
| { | |
| echo "## Deterministic fuzz campaign" | |
| echo "- Shards per module: $shards" | |
| echo "- Generated cases: $((shards * generated_per_shard)) plus checked-in regressions" | |
| echo "- Canonical timeline operations: $((shards * timeline_cases * timeline_steps))" | |
| echo "- IRC matrix result: $IRC_RESULT" | |
| echo "- App matrix result: $APP_RESULT" | |
| } >> "$GITHUB_STEP_SUMMARY" |