Skip to content

Commit

Permalink
Run tests faster in parallel groups on GitHub Actions (#131)
Browse files Browse the repository at this point in the history
* Run tests single-threaded to reduce test brittleness.
* Rename tests to ensure better test timing spread across the alphabet.
  • Loading branch information
bshand authored Nov 22, 2024
1 parent 57038a2 commit 82f2220
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 137 deletions.
69 changes: 69 additions & 0 deletions .github/workflows/static_code_analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
name: Static Code Analysis

on: [pull_request]

jobs:
brakeman:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Ruby + Bundle
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Run Brakeman analysis
run: bundle exec brakeman --parser-timeout 60

bundle-audit:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Ruby + Bundle
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Audit the bundle
# Ignore bootstrap version 3 warning: https://nhsd-jira.digital.nhs.uk/browse/NDRS2-1676
run: bundle exec bundle-audit check --update --ignore CVE-2024-6484
# run: bundle exec bundle-audit check --update

notify:
# Run only on main, but regardless of whether tests past:
if: ${{ always() }}
# if: ${{ always() && github.ref == 'refs/heads/main' }}

needs:
- brakeman
- bundle-audit

runs-on: ubuntu-latest

steps:
- uses: 8398a7/action-slack@v3
with:
status: custom
fields: workflow,commit,author
custom_payload: |
{
channel: '${{ secrets.SLACK_CHANNEL }}',
username: 'GitHub CI',
icon_emoji: ':robot_face:',
attachments: [{
text: '${{ github.event.commits[0].message }}',
fields: [
{ title: 'Author', value: '${{ github.actor }}', short: true },
{ title: 'Revision', value: '${{ github.sha }}', short: true }
]
},{
color: '${{ needs.brakeman.result }}' === 'success' ? 'good' : '${{ needs.brakeman.result }}' === 'failure' ? 'danger' : 'warning',
text: `Brakeman checks returned *${{ needs.brakeman.result }}*.`
},{
color: '${{ needs.bundle-audit.result }}' === 'success' ? 'good' : '${{ needs.bundle-audit.result }}' === 'failure' ? 'danger' : 'warning',
text: `Bundle Audit checks returned *${{ needs.bundle-audit.result }}*.`
}]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
133 changes: 0 additions & 133 deletions .github/workflows/test.yml

This file was deleted.

154 changes: 154 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
# This file is @generated by `bin/rails generate test_strategy test_strategy_timings.csv`
# Please edit the template and regenerate, rather than edit this file.

name: Tests

on: [pull_request]

permissions:
contents: read
actions: read

jobs:
remaining_test_matrix:
strategy:
fail-fast: false
matrix:
ruby-version:
- '3.1.6'
test-group:
- "[a-b]"
- "[c]"
- "[d-m]"
- "[n-z]"

name: "Ruby ${{ matrix.ruby-version }} Tests (${{ matrix.test-group }})"

runs-on: ubuntu-latest

services:
postgres:
image: postgres
env:
POSTGRES_USER: rails
POSTGRES_PASSWORD: rails_password
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
--name postgres
ports:
- 5432:5432

env:
DB_HOST: localhost
DB_PORT: 5432
DB_USERNAME: rails
DB_PASSWORD: rails_password

# Prep the whole stack in test-only mode:
RAILS_ENV: test

steps:
- uses: actions/checkout@v3
- name: Set timezone to Europe/London
run: sudo timedatectl set-timezone Europe/London
- name: Use bundled npm files
run: printf 'disable-self-update-check true\nyarn-offline-mirror "./vendor/npm-packages-offline-cache"\nyarn-offline-mirror-pruning false\n' > .yarnrc
- name: Set up Ruby + Bundle
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
ruby-version: ${{ matrix.ruby-version }}
- name: Inject configuration
run: cp config/database.yml{.ci,}
- name: Prepare the database
run: bin/rails db:setup
- name: Precompile assets
# Since ruby/setup-ruby@v1 moved to Node.js v18 we need the extra options
# until we move to newer webpacker / stop using it.
# I've tried using a newer hash function in config/webpack/environment.js
# by adding the following line, but this didn't help with github actions
# # environment.config.set('output.hashFunction', 'sha256')
# https://stackoverflow.com/questions/69692842/error-message-error0308010cdigital-envelope-routinesunsupported/73465262#73465262
run: NODE_OPTIONS=--openssl-legacy-provider bin/rails yarn:install assets:clobber assets:precompile
- name: Run tests
run: PARALLEL_WORKERS=1 bin/rails test 'test/**/${{ matrix.test-group }}*_test.rb'

# A utility job upon which Branch Protection can depend,
# thus remaining agnostic of the matrix.
remaining_tests:
if: ${{ always() }}
runs-on: ubuntu-latest
# name: Matrix
needs: remaining_test_matrix
steps:
- name: Check build matrix status
if: ${{ needs.remaining_test_matrix.result != 'success' }}
run: exit 1

notify:
# Run only on master, but regardless of whether tests past:
if: ${{ always() }}
# if: ${{ always() && github.ref == 'refs/heads/master' }}

needs:
- remaining_tests

runs-on: ubuntu-latest

steps:
- uses: actions/setup-node@v3
# with:
# node-version: '16.x'
- id: slack-payload-generator
env:
COMMIT_MESSAGE: ${{ github.event.commits[0].message }}
run: |-
node -e "
const passed = '${{ needs.integration_tests.result }}' === 'success' && '${{ needs.models_tests.result }}' === 'success' && '${{ needs.remaining_tests.result }}' === 'success'
const text = process.env.COMMIT_MESSAGE
let attachments = [
{
fallback: text,
text: text,
fields: [
{ title: 'Author', value: '${{ github.actor }}', short: true },
{ title: 'Revision', value: '${{ github.sha }}', short: true }
]
// ts: @commit.author[:time].to_i
}
]
if (passed) {
attachments.push({
color: 'good',
text: 'Tests passed'
})
} else {
attachments.push({
color: 'danger',
text: 'Test(s) failed'
})
}
let payload = {
channel: '${{ secrets.SLACK_CHANNEL }}',
username: 'GitHub CI',
icon_emoji: ':robot_face:',
attachments: attachments
}
console.log('json=' + JSON.stringify(payload))
" >> "$GITHUB_OUTPUT"
- uses: 8398a7/action-slack@v3
with:
status: custom
fields: workflow,commit,author
custom_payload: ${{ steps.slack-payload-generator.outputs.json }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'test_helper'

class CanManageDataItemsTest < ActionDispatch::IntegrationTest
class ManageDataItemsTest < ActionDispatch::IntegrationTest
def setup
@admin = users(:admin_user)
login_and_accept_terms(@admin)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require 'test_helper'
require 'project_helper'

class CanManageDatasetTest < ActionDispatch::IntegrationTest
class ManageDatasetTest < ActionDispatch::IntegrationTest
def setup
@admin = users(:admin_user)
login_and_accept_terms(@admin)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'test_helper'

class CanManageDatasetVersionsTest < ActionDispatch::IntegrationTest
class ManageDatasetVersionsTest < ActionDispatch::IntegrationTest
def setup
@admin = users(:admin_user)
@dataset_manager = users(:team_dataset_manager)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'test_helper'

class CanManageUsersTest < ActionDispatch::IntegrationTest
class ManageUsersTest < ActionDispatch::IntegrationTest
def setup
@admin = users(:admin_user)
login_and_accept_terms(@admin)
Expand Down

0 comments on commit 82f2220

Please sign in to comment.