Skip to content

Nightly fuzz

Nightly fuzz #41

Workflow file for this run

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@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0
with: { distribution: temurin, java-version: 21 }
- uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.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@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0
with: { distribution: temurin, java-version: 21 }
- uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0
- name: Run app generated targets
run: ./gradlew :app:testDebugUnitTest --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/testDebugUnitTest/**
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"