Unit Tests #254
This file contains 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: Unit Tests | |
on: | |
workflow_dispatch: | |
inputs: | |
clearCaches: | |
description: "Clear workflow caches where possible, empty means false" | |
required: false | |
type: string | |
iterations: | |
description: "Number of iterations on each chosen operating system. Default 1. Max 85." | |
required: true | |
default: 1 | |
type: number | |
operatingSystems: | |
description: "Which operating systems to run tests on" | |
required: true | |
type: choice | |
# If you alter system names in default + options here, also alter osArray below to match | |
default: '["windows-latest", "macos-14", "ubuntu-latest"]' | |
options: | |
- '["windows-latest", "macos-14", "ubuntu-latest"]' | |
- '["windows-latest"]' | |
- '["macos-14"]' | |
- '["ubuntu-latest"]' | |
schedule: | |
- cron: "42 0 * * *" | |
pull_request: | |
push: | |
# Ignore merge queue branches on push; avoids merge_group+push concurrency race since ref is same | |
branches-ignore: | |
- 'gh-readonly-queue/**' | |
merge_group: | |
concurrency: | |
# if a workflow is run against the same ref, only one at a time... | |
# ...but allow different triggers to run concurrent (push, manual flake run, scheduled flake run...) | |
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} | |
cancel-in-progress: true | |
jobs: | |
# We want to generate our matrix dynamically | |
# Initial job generates the matrix as a JSON, and following job will use deserialize and use the result | |
matrix_prep: | |
# Do not run the scheduled jobs on forks | |
if: (github.event_name == 'schedule' && github.repository == 'ankidroid/Anki-Android') || (github.event_name != 'schedule') | |
runs-on: ubuntu-latest | |
outputs: | |
matrix: ${{ steps.build-matrix.outputs.result }} | |
steps: | |
- id: build-matrix | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
// by default, we will include all 3 platforms we test on | |
// "latest" would be easy everywhere, but "macos-14" doesn't always happen if you choose "latest" | |
// and we want macos-14 because it has Apple Silicon and is faster | |
// if you alter this, also alter it above in the workflow_dispatch options list | |
let osArray = ["ubuntu-latest", "macos-14", "windows-latest"] | |
// by default, we will run one iteration on each selected system | |
let iterationArray = [1] | |
// workflow dispatch will be a drop-down of different options | |
if (context.eventName === "workflow_dispatch") { | |
const inputs = ${{ toJSON(inputs) }} | |
osArray = JSON.parse(inputs['operatingSystems']) | |
console.log('inputs is: ' + JSON.stringify(inputs)) | |
console.log('osArray is: ' + osArray) | |
const iterationInput = inputs.iterations | |
console.log('iterations input is: ' + iterationInput) | |
// this will expand for example with input 5 => [1, 2, 3, 4, 5] | |
iterationArray = [] | |
for (let i = 1; i <= iterationInput; i++) { | |
iterationArray.push(i); | |
} | |
console.log('iterationArray is: ' + iterationArray) | |
} | |
// If we are running on a schedule it's our periodic passive scan for flakes | |
// Goal is to run enough iterations on all systems that we have confidence there are no flakes | |
if (context.eventName === "schedule") { | |
const iterationCount = 15 | |
for (let i = 1; i <= iterationCount; i++) { | |
iterationArray.push(i); | |
} | |
} | |
let includeArray = []; | |
for(const os of osArray) { | |
// we do this work to define 'name' so we don't need to update branch protection rules | |
// if the os changes, the name is used in the expanded workflow run name, which is then | |
// used as a "required check" on branch protection merge rules, this keeps it stable | |
// even if "macos-14" changes to "macos-15" in the future so we just change the list here | |
// but don't have to go into organization settings / protection rules etc etc | |
includeArray.push({"os": os, "name": os.split('-')[0]}); | |
} | |
return { | |
"os": osArray, | |
"include": includeArray, | |
"iteration": iterationArray | |
} | |
- name: Debug Output | |
run: echo "${{ steps.build-matrix.outputs.result }}" | |
# This uses the matrix generated from the matrix-prep stage | |
# it will run unit tests on whatever OS combinations are desired | |
unit: | |
name: JUnit Tests (${{ matrix.name }} run ${{ matrix.iteration }}) | |
# Do not run the scheduled jobs on forks | |
if: (github.event_name == 'schedule' && github.repository == 'ankidroid/Anki-Android') || (github.event_name != 'schedule') | |
needs: matrix_prep | |
timeout-minutes: 30 | |
env: | |
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
strategy: | |
fail-fast: false | |
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}} | |
runs-on: ${{ matrix.os }} | |
#env: | |
# CODACY_TOKEN: ${{ secrets.CODACY_TOKEN }} | |
steps: | |
- name: Configure Windows Pagefile | |
uses: al-cheb/configure-pagefile-action@v1.4 | |
if: contains(matrix.os, 'windows') | |
with: | |
minimum-size: 8GB | |
maximum-size: 12GB | |
disk-root: "C:" | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 50 | |
- name: Configure JDK | |
uses: actions/setup-java@v4 | |
with: | |
distribution: "temurin" | |
java-version: "21" # also change jitpack.yml | |
- name: Setup Gradle | |
uses: gradle/actions/setup-gradle@v3 | |
timeout-minutes: 5 | |
with: | |
# Only write to the cache for builds on the 'main' branches, stops branches evicting main cache | |
# Builds on other branches will only read from main branch cache writes | |
# Comment this and the with: above out for performance testing on a branch | |
cache-read-only: ${{ github.ref != 'refs/heads/main' }} | |
# gradle-home-cache-cleanup is temporarily disabled to investigate cache pollution issues | |
# Requested in: https://github.com/gradle/actions/issues/167#issuecomment-2052352341 | |
# gradle-home-cache-cleanup: true | |
- name: Clear Caches Optionally | |
if: "${{ github.event.inputs.clearCaches != '' }}" | |
shell: bash | |
run: | | |
du -sk ~/.gradle | |
rm -fr ~/.gradle | |
du -sk ~/.gradle || echo ~/.gradle is gone | |
- name: Gradle Dependency Download | |
uses: nick-invision/retry@v3 | |
with: | |
timeout_minutes: 10 | |
retry_wait_seconds: 60 | |
max_attempts: 3 | |
command: ./gradlew robolectricSdkDownload --daemon | |
- name: Run Unit Tests | |
run: ./gradlew jacocoUnitTestReport --daemon | |
- name: Store Logcat as Artifact | |
# cancelled() handles test timeouts | |
# remove when test timeouts cause a failure() | |
if: failure() || cancelled() | |
uses: actions/upload-artifact@v4 | |
with: | |
name: logcat-${{ matrix.name }}-${{ matrix.iteration }} | |
# look for the `<system-out>` element in the XML files in `test-results` | |
# The folder contains far too much data: | |
# * .bin files | |
# * XML rather than TXT | |
# * Files are mostly JaCoCo issues logged to stderr (#16180) | |
# * All tests are logged, rather than just failures | |
# despite this, it's a great start | |
# look to see if there's a dependency we can use, arther than improving this | |
path: | | |
**/build/test-results/ | |
- name: Stop Gradle | |
if: contains(matrix.os, 'windows') | |
run: ./gradlew --stop | |
- uses: codecov/codecov-action@v4 | |
with: | |
verbose: true |