Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
37db5cd
renaming system integration tests to something more appropriate
Aug 14, 2025
5b4fc97
WIP to isolate unit tests from integration tests
Aug 14, 2025
8756f68
WIP
michaelbrownuc Aug 14, 2025
970cbdd
Merge branch 'main' into ci/ci-fixes
michaelbrownuc Aug 15, 2025
d5315a2
fix typo
michaelbrownuc Aug 15, 2025
9855419
fix after merge from main
michaelbrownuc Aug 15, 2025
bdfc3cf
Merge branch 'main' into ci/ci-fixes
michaelbrownuc Aug 18, 2025
9a8329a
Merged changes from prior PRs into comp-integration
michaelbrownuc Aug 18, 2025
c4a2641
separated integration tests for components into separate workflow
michaelbrownuc Aug 18, 2025
652499a
fixed label
michaelbrownuc Aug 18, 2025
bea692b
cleanup
michaelbrownuc Aug 18, 2025
f473cc3
put system integration tests back on nightly schedule
michaelbrownuc Aug 18, 2025
efcd40f
Put component integration tests back on for push to main
michaelbrownuc Aug 18, 2025
1f7484f
Disable some tests because target is not publicly available.
michaelbrownuc Aug 18, 2025
a97b0f7
appease linter
michaelbrownuc Aug 18, 2025
f795ea6
trying HTTPS instead of SSH
michaelbrownuc Aug 19, 2025
653ec86
Merge branch 'main' into ci/ci-fixes
michaelbrownuc Aug 21, 2025
5ccacee
Merge branch 'main' into ci/ci-fixes
michaelbrownuc Aug 22, 2025
a4a49d0
Merge branch 'main' into ci/ci-fixes
michaelbrownuc Aug 22, 2025
deafcef
disable test with non-public target.
michaelbrownuc Aug 22, 2025
a329446
disable finicky tests
michaelbrownuc Aug 26, 2025
beb1a0e
Merge branch 'main' into ci/ci-fixes
michaelbrownuc Aug 26, 2025
d4549b1
update label for component integration tests.
michaelbrownuc Aug 26, 2025
3511c82
Merge branch 'ci/ci-fixes' of github.com:trailofbits/buttercup into c…
michaelbrownuc Aug 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
361 changes: 361 additions & 0 deletions .github/workflows/comp-integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,361 @@
name: Component Integration Tests

on:
push:
branches:
- main
# Always run full test suite on main branch
pull_request:
# TEMPORARILY REMOVED PATH FILTERING TO DEBUG CI
# Will re-enable after confirming tests pass
schedule:
# Run integration tests daily at 2 AM UTC
- cron: '0 2 * * *'
workflow_dispatch:
inputs:
components:
description: 'Components to test (comma-separated: common,patcher,program-model,seed-gen)'
required: false
default: 'common,patcher,program-model,seed-gen'
type: string
run_integration:
description: 'Run integration tests'
required: false
default: false
type: boolean

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
strategy:
fail-fast: false # Continue running other components even if one fails
matrix:
include:
- component: common
coverage_module: buttercup.common
python: "3.12"
- component: orchestrator
coverage_module: buttercup.orchestrator
python: "3.12"
- component: program-model
coverage_module: buttercup.program_model
python: "3.12"
- component: seed-gen
coverage_module: buttercup.seed_gen
python: "3.12"
- component: patcher
coverage_module: buttercup.patcher
python: "3.12"
- component: fuzzer
coverage_module: buttercup.fuzzer
python: "3.12"
# TODO: Add integration tests back in
# include:
# - component: common
# pytest_args: "--runintegration"
# - component: program-model
# pytest_args: "--runintegration"

runs-on: ubuntu-latest
# Removed if: matrix.should_run since we're not using path filtering right now
services:
redis:
image: redis
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379

steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
submodules: true

- name: Install uv
uses: astral-sh/setup-uv@v6

- name: Setup uv cache
uses: actions/cache@v4
with:
path: |
~/.cache/uv
~/.local/share/uv
key: ${{ runner.os }}-uv-${{ matrix.component }}-${{ hashFiles(format('{0}/uv.lock', matrix.component)) }}
restore-keys: |
${{ runner.os }}-uv-${{ matrix.component }}-
${{ runner.os }}-uv-

- name: Download Wasm runtime
run: wget https://github.com/vmware-labs/webassembly-language-runtimes/releases/download/python%2F3.12.0%2B20231211-040d5a6/python-3.12.0.wasm
if: matrix.component == 'seed-gen'
working-directory: seed-gen

- name: Install dependencies for program-model, seed-gen, and patcher
if: matrix.component == 'program-model' || matrix.component == 'seed-gen' || matrix.component == 'patcher'
run: |
sudo apt-get update
sudo apt-get install -y codequery ripgrep
make install-cscope

- name: Install minimal dependencies
if: matrix.component != 'program-model' && matrix.component != 'seed-gen' && matrix.component != 'patcher' && matrix.component != 'fuzzer'
run: |
sudo apt-get update
sudo apt-get install -y ripgrep

# Fuzzer only needs ripgrep, no codequery
- name: Install fuzzer dependencies
if: matrix.component == 'fuzzer'
run: |
sudo apt-get update
sudo apt-get install -y ripgrep

- name: Prepare environment
run: |
export DEBIAN_FRONTEND=noninteractive
sudo apt-get update
sudo mkdir -p /crs_scratch
sudo chmod -R 777 /crs_scratch

- name: Setup ${{ matrix.component }} component
run: |
uv sync --all-extras --frozen
# Install test reporting tools in isolated environment
# This avoids adding them to every component's dependencies
uv pip install --isolated pytest-html>=4.1.1 pytest-cov>=6.0.0
working-directory: ${{ matrix.component }}

- name: Run tests on ${{ matrix.component }} component
run: |
uv run --frozen pytest -svv ${{ matrix.pytest_args }} \
--junit-xml=test-results.xml \
--html=test-report.html \
--self-contained-html \
--cov=${{ matrix.coverage_module }} \
--cov-report=xml \
--cov-report=html \
--cov-report=term
env:
PYTHON_WASM_BUILD_PATH: "python-3.12.0.wasm"
working-directory: ${{ matrix.component }}

- name: Generate test summary
if: always()
run: |
echo "### Test Results: ${{ matrix.component }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f ${{ matrix.component }}/test-results.xml ]; then
python -c "
import xml.etree.ElementTree as ET
tree = ET.parse('${{ matrix.component }}/test-results.xml')
root = tree.getroot()
tests = root.get('tests', '0')
failures = root.get('failures', '0')
errors = root.get('errors', '0')
skipped = root.get('skipped', '0')
time = root.get('time', '0')
print(f'- **Total Tests**: {tests}')
print(f'- **Passed**: {int(tests) - int(failures) - int(errors) - int(skipped)}')
print(f'- **Failed**: {failures}')
print(f'- **Errors**: {errors}')
print(f'- **Skipped**: {skipped}')
print(f'- **Duration**: {float(time):.2f}s')
" >> $GITHUB_STEP_SUMMARY
else
echo "No test results found" >> $GITHUB_STEP_SUMMARY
fi

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.component }}-py${{ matrix.python }}
path: |
${{ matrix.component }}/test-results.xml
${{ matrix.component }}/test-report.html
${{ matrix.component }}/coverage.xml
${{ matrix.component }}/htmlcov/
retention-days: 30

# Coverage will be uploaded in a separate job after all tests complete

# Consolidated coverage upload after all tests complete
coverage-upload:
needs: [test]
if: always()
runs-on: ubuntu-latest
steps:
- name: Download all coverage reports
uses: actions/download-artifact@v4
with:
pattern: test-results-*
path: coverage-reports

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
directory: coverage-reports
files: '*/coverage.xml,**/coverage.xml'
fail_ci_if_error: false
verbose: true

# Integration tests - run on schedule, manual trigger, or labeled PRs
test-integration:
# Run if:
# - Scheduled run
# - Manual dispatch with run_integration=true
# - PR with 'integration-tests' label
if: |
github.event_name == 'schedule' ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.run_integration == 'true') ||
contains(github.event.pull_request.labels.*.name, 'integration-tests')

strategy:
fail-fast: false
matrix:
include:
- component: common
coverage_module: buttercup.common
python: "3.12"
- component: patcher
coverage_module: buttercup.patcher
python: "3.12"
- component: program-model
coverage_module: buttercup.program_model
python: "3.12"
- component: seed-gen
coverage_module: buttercup.seed_gen
python: "3.12"

runs-on: ubuntu-latest
services:
redis:
image: redis
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379

steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
submodules: true

- name: Check if component should be tested
id: should_test
if: github.event_name == 'workflow_dispatch'
run: |
components="${{ github.event.inputs.components }}"
if [[ -z "$components" ]] || [[ "$components" == *"${{ matrix.component }}"* ]]; then
echo "test=true" >> $GITHUB_OUTPUT
else
echo "test=false" >> $GITHUB_OUTPUT
fi

- name: Install uv
if: steps.should_test.outputs.test != 'false'
uses: astral-sh/setup-uv@v6

- name: Setup uv cache
if: steps.should_test.outputs.test != 'false'
uses: actions/cache@v4
with:
path: |
~/.cache/uv
~/.local/share/uv
key: ${{ runner.os }}-uv-integration-${{ matrix.component }}-${{ hashFiles(format('{0}/uv.lock', matrix.component)) }}
restore-keys: |
${{ runner.os }}-uv-integration-${{ matrix.component }}-
${{ runner.os }}-uv-

- name: Download Wasm runtime
if: matrix.component == 'seed-gen' && steps.should_test.outputs.test != 'false'
run: wget https://github.com/vmware-labs/webassembly-language-runtimes/releases/download/python%2F3.12.0%2B20231211-040d5a6/python-3.12.0.wasm
working-directory: seed-gen

- name: Install integration test dependencies
if: steps.should_test.outputs.test != 'false'
run: |
sudo apt-get update
sudo apt-get install -y codequery ripgrep
make install-cscope

- name: Prepare environment
if: steps.should_test.outputs.test != 'false'
run: |
export DEBIAN_FRONTEND=noninteractive
sudo apt-get update
sudo mkdir -p /crs_scratch
sudo chmod -R 777 /crs_scratch

- name: Setup ${{ matrix.component }} component
if: steps.should_test.outputs.test != 'false'
run: |
uv sync --all-extras --frozen
uv pip install --isolated pytest-html>=4.1.1 pytest-cov>=6.0.0
working-directory: ${{ matrix.component }}

- name: Run integration tests on ${{ matrix.component }}
if: steps.should_test.outputs.test != 'false'
run: |
uv run --frozen pytest -svv --runintegration \
--junit-xml=integration-test-results.xml \
--html=integration-test-report.html \
--self-contained-html \
--cov=${{ matrix.coverage_module }} \
--cov-report=xml:integration-coverage.xml \
--cov-report=html:integration-htmlcov \
--cov-report=term
env:
PYTHON_WASM_BUILD_PATH: "python-3.12.0.wasm"
working-directory: ${{ matrix.component }}
timeout-minutes: 30

- name: Generate integration test summary
if: always() && steps.should_test.outputs.test != 'false'
run: |
echo "### Integration Test Results: ${{ matrix.component }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f ${{ matrix.component }}/integration-test-results.xml ]; then
python -c "
import xml.etree.ElementTree as ET
tree = ET.parse('${{ matrix.component }}/integration-test-results.xml')
root = tree.getroot()
tests = root.get('tests', '0')
failures = root.get('failures', '0')
errors = root.get('errors', '0')
skipped = root.get('skipped', '0')
time = root.get('time', '0')
print(f'- **Total Tests**: {tests}')
print(f'- **Passed**: {int(tests) - int(failures) - int(errors) - int(skipped)}')
print(f'- **Failed**: {failures}')
print(f'- **Errors**: {errors}')
print(f'- **Skipped**: {skipped}')
print(f'- **Duration**: {float(time):.2f}s')
" >> $GITHUB_STEP_SUMMARY
else
echo "No integration test results found" >> $GITHUB_STEP_SUMMARY
fi

- name: Upload integration test results
if: always() && steps.should_test.outputs.test != 'false'
uses: actions/upload-artifact@v4
with:
name: integration-test-results-${{ matrix.component }}-py${{ matrix.python }}
path: |
${{ matrix.component }}/integration-test-results.xml
${{ matrix.component }}/integration-test-report.html
${{ matrix.component }}/integration-coverage.xml
${{ matrix.component }}/integration-htmlcov/
retention-days: 30
2 changes: 1 addition & 1 deletion .github/workflows/integration.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Minikube Integration Tests
name: System Integration Tests

on:
# Daily schedule - 3 AM UTC
Expand Down
Loading
Loading