diff --git a/.github/workflows/miri.yml b/.github/workflows/miri.yml new file mode 100644 index 00000000..c679b31a --- /dev/null +++ b/.github/workflows/miri.yml @@ -0,0 +1,41 @@ +name: PR + +on: + push: + branches: [ main ] + workflow_dispatch: + +permissions: + contents: read + +env: + CARGO_TERM_COLOR: always + +jobs: + miri: + strategy: + matrix: + partition: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + runs-on: ubuntu-latest + + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: dtolnay/rust-toolchain@b95584d8105b9ab200e15821fa671848cf2b7017 # nightly + with: + components: miri + + - name: Install cargo-nextest + run: | + cargo install --locked cargo-nextest + + - name: Run unit tests under Miri + run: | + MIRIFLAGS=-Zmiri-disable-isolation cargo +nightly miri nextest run \ + --partition=hash:${{ matrix.partition }}/10 \ + --test-threads=$(nproc) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 83bb38b5..18fc2d7a 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -2,8 +2,12 @@ name: PR on: push: - branches: [ "main" ] + branches: [ main ] pull_request: + workflow_dispatch: + +permissions: + contents: read env: CARGO_TERM_COLOR: always @@ -117,3 +121,32 @@ jobs: echo "::error::CLI Cargo.lock is out of date. Please run 'cargo update' in the cli directory and commit the changes." exit 1 fi + + miri: + strategy: + matrix: + partition: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + runs-on: ubuntu-latest + + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - uses: dtolnay/rust-toolchain@b95584d8105b9ab200e15821fa671848cf2b7017 # nightly + with: + components: "miri, rust-src" + - uses: cargo-bins/cargo-binstall@main + - name: Install cargo-nextest + run: | + cargo binstall cargo-nextest --secure + + - name: Run unit tests under Miri + run: | + MIRIFLAGS=-Zmiri-disable-isolation PROPTEST_CASES=16 cargo +nightly miri nextest run \ + --partition=hash:${{ matrix.partition }}/10 \ + --test-threads=$(nproc) diff --git a/src/database.rs b/src/database.rs index f373e262..076d0ede 100644 --- a/src/database.rs +++ b/src/database.rs @@ -384,6 +384,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "persistence is not implemented with miri")] fn test_data_persistence() { let tmp_dir = TempDir::new("test_db").unwrap(); let file_path = tmp_dir.path().join("test.db"); diff --git a/src/executor/threadpool.rs b/src/executor/threadpool.rs index 437a3299..7d4a08b5 100644 --- a/src/executor/threadpool.rs +++ b/src/executor/threadpool.rs @@ -61,6 +61,7 @@ mod tests { use std::panic; #[test] + #[cfg_attr(miri, ignore = "crossbeam (used by rayon) does not play nicely with miri")] fn defer() { let pool = builder().build().expect("building thread pool failed"); let future = pool.defer(|| 123); @@ -68,6 +69,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "crossbeam (used by rayon) does not play nicely with miri")] fn poisoning() { let pool = builder().build().expect("building thread pool failed"); let future = pool.defer(|| panic!("something went wrong")); diff --git a/src/meta/mod.rs b/src/meta/mod.rs index db7bc1d6..f46e70cf 100644 --- a/src/meta/mod.rs +++ b/src/meta/mod.rs @@ -675,6 +675,7 @@ mod tests { use crate::page::page_id; #[test] + #[cfg_attr(miri, ignore = "persistence is not implemented with miri")] fn persistence() { let f = tempfile::tempfile().expect("failed to open temporary file"); let mut manager = @@ -875,6 +876,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "persistence is not implemented with miri")] fn crash_recovery() { let f = tempfile::tempfile().expect("failed to open temporary file"); let mut manager = diff --git a/src/page/manager/options.rs b/src/page/manager/options.rs index f95cc20d..bc29d9dc 100644 --- a/src/page/manager/options.rs +++ b/src/page/manager/options.rs @@ -18,10 +18,12 @@ impl PageManagerOptions { let max_pages = if cfg!(not(test)) { Page::MAX_COUNT - } else { + } else if cfg!(not(miri)) { // Because tests run in parallel, it's easy to exhaust the address space, so use a more // conservative limit Page::MAX_COUNT / 1024 + } else { + 2048 }; Self { open_options, page_count: 0, max_pages }