1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
name: CI
on:
push:
branches:
- main
pull_request:
branches:
- main
# The fuzz job only. Coverage-guided fuzzing gets better the longer it runs
# and finds nothing new most nights, so it does not belong on the path of a
# pull request; the seed corpus it produces is what guards those, through
# `tests/fuzz_seeds.rs` in the `lint-test` job above.
schedule:
- cron: '0 5 * * *'
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
CXX: g++
jobs:
lint-test:
name: Rust ${{ matrix.toolchain }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
toolchain:
steps:
- name: Checkout sources
uses: actions/checkout@v4
# Only a C++ compiler: `build.rs` shells out to `$CXX` for the Glaze
# interop fixtures and links nothing native. The `mat` feature's HDF5
# stack is `hdf5-pure`, which is pure Rust, so no libhdf5 is involved.
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y g++
- name: Install toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.toolchain }}
components: clippy, rustfmt
- name: Cache cargo artifacts
uses: Swatinem/rust-cache@v2
- name: cargo fmt --check
if: matrix.toolchain == 'stable'
run: cargo fmt --all -- --check
- name: cargo clippy (all features)
run: cargo clippy --locked --all-targets --all-features -- -D warnings
- name: cargo test (all features)
run: cargo test --locked --all --all-features
# Guard the default (mat-off) build: it is what most consumers get, and it
# is the only configuration that compiles the `#[cfg(not(feature = "mat"))]`
# paths, which `--all-features` never exercises.
- name: cargo clippy (default features)
if: matrix.toolchain == 'stable'
run: cargo clippy --locked --all-targets -- -D warnings
- name: cargo test (default features)
if: matrix.toolchain == 'stable'
run: cargo test --locked
msrv:
name: MSRV (Rust 1.96.1)
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y g++
- name: Install Rust 1.96.1
uses: dtolnay/rust-toolchain@1.96.1
- name: Cache cargo artifacts
uses: Swatinem/rust-cache@v2
- name: cargo check (all features)
run: cargo check --locked --all-targets --all-features
- name: cargo check (default features)
run: cargo check --locked --all-targets
# Runs the test suite on a big-endian target (s390x) under emulation, so the
# little-endian/big-endian `#[cfg(target_endian)]` branches in the bulk
# typed/complex codecs are actually exercised, not just compiled on LE. Uses
# the default feature set (the `mat`/HDF5 stack is irrelevant to endianness and
# not cross-built here).
big-endian:
name: Big-endian (s390x)
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Install toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo artifacts
uses: Swatinem/rust-cache@v2
- name: Install cross
run: cargo install cross --locked --version 0.2.5
# `num-complex` explicitly: the bulk complex codec is the byte-order
# sensitive path this job exists for, and its tests are behind that
# feature. `mat` stays off; hdf5-pure has its own big-endian job.
- name: cargo test on s390x (big-endian)
run: cross test --locked --target s390x-unknown-linux-gnu --features num-complex
# Coverage-guided fuzzing, nightly-only because cargo-fuzz needs the sanitizer
# flags. Each target starts from the committed seeds, runs for a few minutes,
# and uploads whatever crashed. A crash found here becomes a permanent stable
# test by being minimised and moved into `fuzz/seeds/<target>/`.
fuzz:
name: Fuzz (${{ matrix.target }})
# Scheduled and manual runs only. `always()` is deliberately not used: this
# should not run on every push, and it must not gate a pull request.
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Install nightly
uses: dtolnay/rust-toolchain@nightly
- name: Cache cargo artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: ". -> target\n fuzz -> fuzz/target"
- name: Install cargo-fuzz
run: cargo install cargo-fuzz --locked
# `-rss_limit_mb` is libFuzzer's own ceiling and is independent of the
# allocation bound the targets assert; it catches a runaway that the
# in-process check would only see after the fact.
- name: Fuzz ${{ matrix.target }}
run: |
mkdir -p fuzz/corpus/${{ matrix.target }}
cargo fuzz run ${{ matrix.target }} \
fuzz/corpus/${{ matrix.target }} fuzz/seeds/${{ matrix.target }} \
-- -max_total_time=300 -rss_limit_mb=2048
- name: Upload crash artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: fuzz-artifacts-${{ matrix.target }}
path: fuzz/artifacts/
if-no-files-found: ignore