chore: approach Node.js' "suites and tests" way of testing (#328)

This commit is contained in:
Paulo F. Oliveira
2025-04-26 23:54:49 +01:00
committed by GitHub
parent 4b97eeaf23
commit 8e3c26cc73
5 changed files with 797 additions and 864 deletions
+2 -38
View File
@@ -69,47 +69,11 @@ jobs:
- otp-version: '26' - otp-version: '26'
rebar3-version: 'nightly' rebar3-version: 'nightly'
os: 'ubuntu-latest' os: 'ubuntu-latest'
- elixir-version: 'v1.6' - gleam-version: '1.9.0'
otp-version: '21'
rebar3-version: '3.12'
os: 'ubuntu-20.04'
- elixir-version: 'v1.7'
otp-version: '22'
rebar3-version: '3.13'
os: 'ubuntu-20.04'
- elixir-version: 'v1.10'
otp-version: '23'
rebar3-version: '3.14'
os: 'ubuntu-20.04'
- elixir-version: 'v1.13.4'
otp-version: '25.0.2'
rebar3-version: '3.19'
os: 'ubuntu-20.04'
- elixir-version: 'v1.12'
otp-version: '24'
rebar3-version: '3.15'
os: 'ubuntu-20.04'
- elixir-version: 'v1.11.0'
otp-version: '22.3.4.2'
os: 'ubuntu-20.04'
version-type: 'strict'
- elixir-version: '1.10.3'
otp-version: '22.3.4.1'
os: 'ubuntu-20.04'
version-type: 'strict'
- elixir-version: 'main'
otp-version: '23.1'
os: 'ubuntu-20.04'
version-type: 'strict'
- elixir-version: 'main'
otp-version: '25'
os: 'ubuntu-20.04'
version-type: 'strict'
- gleam-version: '1.5.1'
otp-version: '27' otp-version: '27'
os: 'ubuntu-latest' os: 'ubuntu-latest'
disable_problem_matchers: true disable_problem_matchers: true
- gleam-version: '1.5.1' - gleam-version: '1.9.0'
otp-version: false otp-version: false
os: 'ubuntu-latest' os: 'ubuntu-latest'
disable_problem_matchers: true disable_problem_matchers: true
+1 -1
View File
@@ -58,7 +58,7 @@ jobs:
otp-version: '24' otp-version: '24'
rebar3-version: '3.15' rebar3-version: '3.15'
os: 'windows-latest' os: 'windows-latest'
- gleam-version: '1.5.1' - gleam-version: '1.9.0'
otp-version: '27' otp-version: '27'
os: 'windows-latest' os: 'windows-latest'
- elixir-version: 'v1.13' - elixir-version: 'v1.13'
+9 -9
View File
@@ -106,7 +106,7 @@ jobs:
test: test:
runs-on: self-hosted runs-on: self-hosted
env: env:
ImageOS: ubuntu20 # equivalent to runs-on ubuntu-20.04 ImageOS: ubuntu24 # equivalent to runs-on ubuntu-24.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: erlef/setup-beam@v1 - uses: erlef/setup-beam@v1
@@ -241,12 +241,12 @@ on: push
jobs: jobs:
test: test:
runs-on: ubuntu-20.04 runs-on: ubuntu-24.04
name: OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} name: OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}}
strategy: strategy:
matrix: matrix:
otp: ['21.1', '22.2', '23.3'] otp: ['25.3.2', '26.2.5', '27.3.3']
elixir: ['1.8.2', '1.9.4'] elixir: ['1.17.3', '1.18.3']
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: erlef/setup-beam@v1 - uses: erlef/setup-beam@v1
@@ -265,12 +265,12 @@ on: push
jobs: jobs:
test: test:
runs-on: ubuntu-20.04 runs-on: ubuntu-24.04
name: Erlang/OTP ${{matrix.otp}} / rebar3 ${{matrix.rebar3}} name: Erlang/OTP ${{matrix.otp}} / rebar3 ${{matrix.rebar3}}
strategy: strategy:
matrix: matrix:
otp: ['21.1', '22.2', '23.3'] otp: ['25.3.2', '26.2.5', '27.3.3']
rebar3: ['3.14.1', '3.14.3'] rebar3: ['3.23.0', '3.24.0']
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: erlef/setup-beam@v1 - uses: erlef/setup-beam@v1
@@ -312,7 +312,7 @@ jobs:
- uses: erlef/setup-beam@v1 - uses: erlef/setup-beam@v1
with: with:
otp-version: '27' otp-version: '27'
gleam-version: '1.5.1' gleam-version: '1.9.0'
- run: gleam test - run: gleam test
``` ```
@@ -330,7 +330,7 @@ jobs:
- uses: erlef/setup-beam@v1 - uses: erlef/setup-beam@v1
with: with:
otp-version: false otp-version: false
gleam-version: '1.5.1' gleam-version: '1.9.0'
- run: gleam check - run: gleam check
``` ```
+1 -1
View File
@@ -9,7 +9,7 @@
"licenses": "yarn licenses generate-disclaimer > 3RD_PARTY_LICENSES", "licenses": "yarn licenses generate-disclaimer > 3RD_PARTY_LICENSES",
"markdownlint": "markdownlint *.md ./github/**/*.md", "markdownlint": "markdownlint *.md ./github/**/*.md",
"shellcheck": "shellcheck .github/workflows/*.sh", "shellcheck": "shellcheck .github/workflows/*.sh",
"test": "node test/setup-beam.test.js", "test": "node --test --test-reporter=spec",
"yamllint": "yamllint .github/workflows/**.yml && yamllint .*.yml && yamllint *.yml", "yamllint": "yamllint .github/workflows/**.yml && yamllint .*.yml && yamllint *.yml",
"clean-dist": "rm -rf ./dist", "clean-dist": "rm -rf ./dist",
"lint": "npm run markdownlint && npm run shellcheck && npm run yamllint && npm run jslint", "lint": "npm run markdownlint && npm run shellcheck && npm run yamllint && npm run jslint",
+73 -104
View File
@@ -12,9 +12,9 @@ const http = require('http')
const fs = require('fs') const fs = require('fs')
const os = require('os') const os = require('os')
const path = require('path') const path = require('path')
const core = require('@actions/core')
const setupBeam = require('../src/setup-beam') const setupBeam = require('../src/setup-beam')
const { problemMatcher } = require('../matchers/elixir-matchers.json') const { problemMatcher } = require('../matchers/elixir-matchers.json')
const { describe, it } = require('node:test')
const matrix = { const matrix = {
otp: { otp: {
@@ -58,33 +58,11 @@ function parseReleases(version) {
} }
} }
async function all() { describe('OTP install', () => {
await testFailInstallOTP() it('fails for invalid OS version', async () => {
await testFailInstallElixir()
await testFailInstallGleam()
await testFailInstallRebar3()
await testFailGetOTPVersion()
await testOTPVersions()
await testLinuxARM64OTPVersions()
await testLinuxAMD64OTPVersions()
await testElixirVersions()
await testGleamVersions()
await testRebar3Versions()
await testGetVersionFromSpec()
await testParseVersionFile()
await testGetRetry()
await testElixirMixCompileError()
await testElixirMixCompileWarning()
await testElixirMixTestFailure()
await testElixirCredoOutputDefault()
}
async function testFailInstallOTP() {
const otpOSVersion = 'ubuntu-08.04' const otpOSVersion = 'ubuntu-08.04'
const otpVersion = 'OTP-23.2' const otpVersion = 'OTP-23.2'
assert.rejects( assert.rejects(
async () => { async () => {
await setupBeam.install('otp', { await setupBeam.install('otp', {
@@ -99,12 +77,12 @@ async function testFailInstallOTP() {
}, },
`Installing Erlang/OTP ${otpVersion} over ${otpOSVersion} is supposed to fail`, `Installing Erlang/OTP ${otpVersion} over ${otpOSVersion} is supposed to fail`,
) )
} })
})
async function testFailInstallElixir() { describe('Elixir install', () => {
let exVersion it('fails for version 0.11 without OTP', async () => {
const exVersion = '0.11'
exVersion = '0.11'
assert.rejects( assert.rejects(
async () => { async () => {
await setupBeam.install('elixir', { await setupBeam.install('elixir', {
@@ -118,8 +96,10 @@ async function testFailInstallElixir() {
}, },
`Installing Elixir ${exVersion} is supposed to fail`, `Installing Elixir ${exVersion} is supposed to fail`,
) )
})
exVersion = 'v1.0.0-otp-17' it('fails for version 1.0.0 on OTP 17 (without OTP)', async () => {
const exVersion = 'v1.0.0-otp-17'
assert.rejects( assert.rejects(
async () => { async () => {
await setupBeam.install('elixir', { await setupBeam.install('elixir', {
@@ -133,9 +113,11 @@ async function testFailInstallElixir() {
}, },
`Installing Elixir ${exVersion} is supposed to fail`, `Installing Elixir ${exVersion} is supposed to fail`,
) )
} })
})
async function testFailInstallGleam() { describe('Gleam install', () => {
it('fails for unknown OTP', async () => {
const gleamVersion = '0.1.3' const gleamVersion = '0.1.3'
assert.rejects( assert.rejects(
async () => { async () => {
@@ -147,9 +129,11 @@ async function testFailInstallGleam() {
}, },
`Installing Gleam ${gleamVersion} is supposed to fail`, `Installing Gleam ${gleamVersion} is supposed to fail`,
) )
} })
})
async function testFailInstallRebar3() { describe('rebar3 install', () => {
it('fails for unknown OTP', async () => {
const r3Version = '0.14.4' const r3Version = '0.14.4'
assert.rejects( assert.rejects(
async () => { async () => {
@@ -161,9 +145,10 @@ async function testFailInstallRebar3() {
}, },
`Installing rebar3 ${r3Version} is supposed to fail`, `Installing rebar3 ${r3Version} is supposed to fail`,
) )
} })
})
async function testOTPVersions() { describe('.getOTPVersion(_) - Erlang', () => {
let got let got
let expected let expected
let spec let spec
@@ -174,11 +159,12 @@ async function testOTPVersions() {
'https://repo.hex.pm, https://cdn.jsdelivr.net/hex', 'https://repo.hex.pm, https://cdn.jsdelivr.net/hex',
{ multiline: true }, { multiline: true },
) )
const previousRunnerArch = process.env.RUNNER_ARCH
if (process.platform === 'linux') { if (process.platform === 'linux') {
const previousRunnerArch = process.env.RUNNER_ARCH
process.env.RUNNER_ARCH = 'X64' process.env.RUNNER_ARCH = 'X64'
it('is Ok for known linux version', async () => {
before = simulateInput('version-type', 'strict') before = simulateInput('version-type', 'strict')
spec = '26' spec = '26'
osVersion = 'ubuntu-24.04' osVersion = 'ubuntu-24.04'
@@ -262,11 +248,11 @@ async function testOTPVersions() {
expected = 'master' expected = 'master'
got = await setupBeam.getOTPVersion(spec, osVersion) got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
})
process.env.RUNNER_ARCH = previousRunnerArch
} }
if (process.platform === 'win32') { if (process.platform === 'win32') {
it('is Ok for known win32 version', async () => {
spec = '24.0.1' spec = '24.0.1'
osVersion = 'windows-latest' osVersion = 'windows-latest'
expected = '24.0.1' expected = '24.0.1'
@@ -307,28 +293,15 @@ async function testOTPVersions() {
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
simulateInput('otp-architecture', before) simulateInput('otp-architecture', before)
})
} }
simulateInput('hexpm-mirrors', hexMirrors, { multiline: true }) if (process.platform === 'linux') {
} it('is Ok for known linux ARM64 version', async () => {
async function testLinuxARM64OTPVersions() {
let got
let expected
let spec
let osVersion
let before
const hexMirrors = simulateInput(
'hexpm-mirrors',
'https://repo.hex.pm, https://cdn.jsdelivr.net/hex',
{ multiline: true },
)
const arm64Options = setupBeam.githubARMRunnerArchs() const arm64Options = setupBeam.githubARMRunnerArchs()
process.env.RUNNER_ARCH = process.env.RUNNER_ARCH =
arm64Options[Math.floor(Math.random() * arm64Options.length)] arm64Options[Math.floor(Math.random() * arm64Options.length)]
if (process.platform === 'linux') {
before = simulateInput('version-type', 'strict') before = simulateInput('version-type', 'strict')
spec = '26' spec = '26'
osVersion = 'ubuntu-24.04' osVersion = 'ubuntu-24.04'
@@ -394,28 +367,13 @@ async function testLinuxARM64OTPVersions() {
expected = 'master' expected = 'master'
got = await setupBeam.getOTPVersion(spec, osVersion) got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
} })
simulateInput('hexpm-mirrors', hexMirrors, { multiline: true })
}
async function testLinuxAMD64OTPVersions() {
let got
let expected
let spec
let osVersion
let before
const hexMirrors = simulateInput(
'hexpm-mirrors',
'https://repo.hex.pm, https://cdn.jsdelivr.net/hex',
{ multiline: true },
)
it('is Ok for known linux AMD64 version', async () => {
const amd64Options = setupBeam.githubAMDRunnerArchs() const amd64Options = setupBeam.githubAMDRunnerArchs()
process.env.RUNNER_ARCH = process.env.RUNNER_ARCH =
amd64Options[Math.floor(Math.random() * amd64Options.length)] amd64Options[Math.floor(Math.random() * amd64Options.length)]
if (process.platform === 'linux') {
before = simulateInput('version-type', 'strict') before = simulateInput('version-type', 'strict')
spec = '26' spec = '26'
osVersion = 'ubuntu-24.04' osVersion = 'ubuntu-24.04'
@@ -499,12 +457,15 @@ async function testLinuxAMD64OTPVersions() {
expected = 'master' expected = 'master'
got = await setupBeam.getOTPVersion(spec, osVersion) got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
})
} }
simulateInput('hexpm-mirrors', hexMirrors, { multiline: true }) simulateInput('hexpm-mirrors', hexMirrors, { multiline: true })
} process.env.RUNNER_ARCH = previousRunnerArch
})
async function testFailGetOTPVersion() { describe('OTP arch-specific install', () => {
it('fails for invalid GitHub runner arch.', async () => {
const previousRunnerArch = process.env.RUNNER_ARCH const previousRunnerArch = process.env.RUNNER_ARCH
process.env.RUNNER_ARCH = 'invalid' process.env.RUNNER_ARCH = 'invalid'
@@ -524,9 +485,10 @@ async function testFailGetOTPVersion() {
) )
} }
process.env.RUNNER_ARCH = previousRunnerArch process.env.RUNNER_ARCH = previousRunnerArch
} })
})
async function testElixirVersions() { describe('.getOTPVersion(_) - Elixir', () => {
let got let got
let expected let expected
let spec let spec
@@ -536,6 +498,7 @@ async function testElixirVersions() {
multiline: true, multiline: true,
}) })
it('returns the expected value', async () => {
spec = '1.1.x' spec = '1.1.x'
otpVersion = 'OTP-17' otpVersion = 'OTP-17'
expected = 'v1.1.1-otp-17' expected = 'v1.1.1-otp-17'
@@ -593,16 +556,18 @@ async function testElixirVersions() {
got = await setupBeam.getElixirVersion(spec, otpVersion) got = await setupBeam.getElixirVersion(spec, otpVersion)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
simulateInput('version-type', before) simulateInput('version-type', before)
})
simulateInput('hexpm-mirrors', hexMirrors, { multiline: true }) simulateInput('hexpm-mirrors', hexMirrors, { multiline: true })
} })
async function testGleamVersions() { describe('.getOTPVersion(_) - Gleam', () => {
let got let got
let expected let expected
let spec let spec
let otpVersion let otpVersion
it('returns the expected value', async () => {
spec = 'v0.3.0' spec = 'v0.3.0'
otpVersion = 'OTP-23' otpVersion = 'OTP-23'
expected = 'v0.3.0' expected = 'v0.3.0'
@@ -622,13 +587,15 @@ async function testGleamVersions() {
got = await setupBeam.getGleamVersion(spec, otpVersion) got = await setupBeam.getGleamVersion(spec, otpVersion)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
simulateInput('version-type', before) simulateInput('version-type', before)
} })
})
async function testRebar3Versions() { describe('.getOTPVersion(_) - rebar3', () => {
let got let got
let expected let expected
let spec let spec
it('returns the expected value', async () => {
spec = '3.10.x' spec = '3.10.x'
expected = '3.10.0' expected = '3.10.0'
got = await setupBeam.getRebar3Version(spec) got = await setupBeam.getRebar3Version(spec)
@@ -643,9 +610,10 @@ async function testRebar3Versions() {
expected = '3.10.0' expected = '3.10.0'
got = await setupBeam.getRebar3Version(spec) got = await setupBeam.getRebar3Version(spec)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
} })
})
async function testGetVersionFromSpec() { describe('.getVersionFromSpec(_)', () => {
let got let got
let expected let expected
let spec let spec
@@ -691,6 +659,7 @@ async function testGetVersionFromSpec() {
versions[version] = version versions[version] = version
}) })
it('returns the expected value', async () => {
spec = '1' spec = '1'
expected = '1.1.0' expected = '1.1.0'
got = setupBeam.getVersionFromSpec(spec, versions) got = setupBeam.getVersionFromSpec(spec, versions)
@@ -887,14 +856,16 @@ async function testGetVersionFromSpec() {
expected = '3.23.0' expected = '3.23.0'
got = setupBeam.getVersionFromSpec(spec, matrix.rebar3) got = setupBeam.getVersionFromSpec(spec, matrix.rebar3)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
} })
})
async function testParseVersionFile() { describe('version file', () => {
const otpVersion = unsimulateInput('otp-version') const otpVersion = unsimulateInput('otp-version')
const elixirVersion = unsimulateInput('elixir-version') const elixirVersion = unsimulateInput('elixir-version')
const gleamVersion = unsimulateInput('gleam-version') const gleamVersion = unsimulateInput('gleam-version')
const rebar3Version = unsimulateInput('rebar3-version') const rebar3Version = unsimulateInput('rebar3-version')
it('is parsed correctly', async () => {
const erlang = '27' const erlang = '27'
const elixir = '1.17.0' const elixir = '1.17.0'
const gleam = '0.23.0' const gleam = '0.23.0'
@@ -931,14 +902,16 @@ gleam ${gleam} \nrebar ${rebar3}`
assert.ok(async () => { assert.ok(async () => {
await setupBeam.install('rebar3', { toolVersion: rebar3 }) await setupBeam.install('rebar3', { toolVersion: rebar3 })
}) })
})
simulateInput('otp-version', otpVersion) simulateInput('otp-version', otpVersion)
simulateInput('elixir-version', elixirVersion) simulateInput('elixir-version', elixirVersion)
simulateInput('gleam-version', gleamVersion) simulateInput('gleam-version', gleamVersion)
simulateInput('rebar3-version', rebar3Version) simulateInput('rebar3-version', rebar3Version)
} })
async function testGetRetry() { describe('.get(_)', () => {
it('retries as expected', async () => {
let attempt = 0 let attempt = 0
const server = http.createServer((req, res) => { const server = http.createServer((req, res) => {
attempt++ attempt++
@@ -958,9 +931,11 @@ async function testGetRetry() {
} finally { } finally {
server.close() server.close()
} }
} })
})
async function testElixirMixCompileError() { describe("Elixir Mix matcher's", () => {
it('errors are properly matched', async () => {
const [matcher] = problemMatcher.find( const [matcher] = problemMatcher.find(
({ owner }) => owner === 'elixir-mixCompileError', ({ owner }) => owner === 'elixir-mixCompileError',
).pattern ).pattern
@@ -970,9 +945,9 @@ async function testElixirMixCompileError() {
assert.equal(file, 'lib/test.ex') assert.equal(file, 'lib/test.ex')
assert.equal(line, '16') assert.equal(line, '16')
assert.equal(message, output) assert.equal(message, output)
} })
async function testElixirMixCompileWarning() { it('warnings are properly matched', async () => {
const [messagePattern, filePattern] = problemMatcher.find( const [messagePattern, filePattern] = problemMatcher.find(
({ owner }) => owner === 'elixir-mixCompileWarning', ({ owner }) => owner === 'elixir-mixCompileWarning',
).pattern ).pattern
@@ -990,9 +965,9 @@ async function testElixirMixCompileWarning() {
const [, file, line] = secondOutput.match(filePattern.regexp) const [, file, line] = secondOutput.match(filePattern.regexp)
assert.equal(file, 'lib/test.ex') assert.equal(file, 'lib/test.ex')
assert.equal(line, '16') assert.equal(line, '16')
} })
async function testElixirMixTestFailure() { it('failures are properly matched', async () => {
const [messagePattern, filePattern] = problemMatcher.find( const [messagePattern, filePattern] = problemMatcher.find(
({ owner }) => owner === 'elixir-mixTestFailure', ({ owner }) => owner === 'elixir-mixTestFailure',
).pattern ).pattern
@@ -1006,9 +981,9 @@ async function testElixirMixTestFailure() {
const [, file, line] = secondOutput.match(filePattern.regexp) const [, file, line] = secondOutput.match(filePattern.regexp)
assert.equal(file, 'test/test_test.exs') assert.equal(file, 'test/test_test.exs')
assert.equal(line, '9') assert.equal(line, '9')
} })
async function testElixirCredoOutputDefault() { it('Credo output is properly matched', async () => {
const [messagePattern, filePattern] = problemMatcher.find( const [messagePattern, filePattern] = problemMatcher.find(
({ owner }) => owner === 'elixir-credoOutputDefault', ({ owner }) => owner === 'elixir-credoOutputDefault',
).pattern ).pattern
@@ -1023,7 +998,8 @@ async function testElixirCredoOutputDefault() {
assert.equal(file, 'lib/test.ex') assert.equal(file, 'lib/test.ex')
assert.equal(line, '15') assert.equal(line, '15')
assert.equal(column, '7') assert.equal(column, '7')
} })
})
function unsimulateInput(key) { function unsimulateInput(key) {
return simulateInput(key, '') return simulateInput(key, '')
@@ -1047,10 +1023,3 @@ function simulateInput(key, value0, opts) {
function input(key) { function input(key) {
return `INPUT_${key.replace(/ /g, '_').toUpperCase()}` return `INPUT_${key.replace(/ /g, '_').toUpperCase()}`
} }
all()
.then(() => process.exit(0))
.catch((err) => {
core.error(err)
process.exit(1)
})