Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 83 additions & 32 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ jobs:
exit 1
fi

build_and_test:
name: Build and Test
build:
name: Build
needs: [check_action_pins, static_checks]
runs-on: ${{ matrix.os }}
strategy:
Expand Down Expand Up @@ -134,10 +134,6 @@ jobs:
- name: Build
run: cargo build --workspace --release --verbose

- name: Test
timeout-minutes: 10
run: cargo test --workspace --lib --verbose

- name: Package binaries
if: github.event_name == 'workflow_dispatch' && github.event.inputs.upload_artifacts == 'true'
run: |
Expand All @@ -151,10 +147,28 @@ jobs:
name: ${{ runner.os }}-binary
path: artifacts/

unit_tests:
name: Unit Tests
runs-on: [self-hosted, Linux, X64, nixos]
needs: [build, check_flake_lock]
steps:
- name: Checkout repository
uses: actions/checkout@v5

- name: Run unit tests with coverage
timeout-minutes: 10
run: nix run -L .#internal.x86_64-linux.coverage-unit-tests

- name: Upload coverage
uses: actions/upload-artifact@v5
with:
name: coverage-unit
path: unit.lcov

platform_integration_tests:
name: Platform Integration Tests
runs-on: [self-hosted, Linux, X64, nixos]
needs: [check_flake_lock]
needs: [build, check_flake_lock]
steps:
- name: Checkout repository
uses: actions/checkout@v5
Expand All @@ -164,12 +178,20 @@ jobs:
env:
CARDANO_NODE_SOCKET_PATH: /run/cardano-node/node_preview.socket
BLOCKFROST_PREVIEW_PROJECT_ID: ${{ secrets.BLOCKFROST_PREVIEW_PROJECT_ID }}
run: nix develop .# --command cargo test --verbose -p blockfrost-platform-integration-tests --no-fail-fast
run: nix run -L .#internal.x86_64-linux.coverage-platform-integ-tests

- name: Upload coverage
uses: actions/upload-artifact@v5
with:
name: coverage-platform-integ
path: platform-integ.lcov

blockfrost_integration_tests:
name: ${{ matrix.mode == 'ignore-check' && 'Ignored' || 'Tests' }} (${{ matrix.network }})
name: >-
${{ matrix.mode == 'ignore-check' && 'Ignored'
|| 'Tests' }} (${{ matrix.network }})
runs-on: [self-hosted, Linux, X64, nixos]
needs: [check_flake_lock]
needs: [build, check_flake_lock]
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -202,34 +224,21 @@ jobs:
SUBMIT_MNEMONIC: ${{ secrets[matrix.submit_mnemonic_secret] }}
DOLOS_ENDPOINT: ${{ matrix.dolos_endpoint }}
CARDANO_NODE_SOCKET_PATH: ${{ matrix.cardano_node_socket_path }}
LLVM_PROFILE_FILE: ${{ github.workspace }}/blockfrost-%p-%m.profraw
run: |
target=${{ matrix.mode == 'ignore-check' && 'blockfrost-ignore-check' || 'blockfrost-tests' }}
nix run -L .#internal.x86_64-linux."${target}-${{ matrix.network }}"

coverage:
name: Coverage
runs-on: ubuntu-latest
needs: [check_action_pins]
steps:
- name: Checkout repository
uses: actions/checkout@v5

- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@150fca883cd4034361b621bd4e6a9d34e5143606 # v1

- name: Cache Cargo build
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
shared-key: coverage
- name: Convert profraw to LCOV
if: matrix.mode != 'ignore-check'
run: nix run -L .#internal.x86_64-linux.coverage-convert-blockfrost

- name: Install cargo-tarpaulin
uses: taiki-e/install-action@c070f87102a1c75b3183910f391c1cb887fe13c8 # v2.77.6
- name: Upload coverage
if: matrix.mode != 'ignore-check'
uses: actions/upload-artifact@v5
with:
tool: cargo-tarpaulin

- name: Check coverage
timeout-minutes: 10
run: cargo tarpaulin --workspace --all --lib --features tarpaulin --fail-under 8
name: coverage-blockfrost-${{ matrix.network }}
path: blockfrost.lcov

oci_build:
name: OCI Build (${{ matrix.arch }})
Expand Down Expand Up @@ -333,3 +342,45 @@ jobs:

set -x
docker buildx imagetools create "${args[@]}" "${amd}" "${arm}"

coverage_report:
name: Coverage Report
runs-on: [self-hosted, Linux, X64, nixos]
if: always()
needs:
- unit_tests
- platform_integration_tests
- blockfrost_integration_tests
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0 # needed for git diff against origin/main

- name: Download coverage artifacts
uses: actions/download-artifact@v5
with:
pattern: coverage-*
merge-multiple: true

- name: Restore Hydra nightly coverage from cache
id: hydra-cache
uses: actions/cache/restore@v4
with:
path: hydra-combined.lcov
key: hydra-coverage-impossible-exact-match
restore-keys: hydra-coverage-

- name: Generate coverage report
run: |
args=(--threshold 11)
if [ -f hydra-combined.lcov ]; then
args+=(--filter-hydra hydra-combined.lcov --filter-base origin/main)
fi
nix run -L .#internal.x86_64-linux.coverage-report -- "${args[@]}"

- name: Upload HTML report
uses: actions/upload-artifact@v5
with:
name: coverage-report
path: coverage-html/
60 changes: 60 additions & 0 deletions .github/workflows/hydra-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,22 @@ jobs:
CARDANO_NODE_SOCKET_PATH: /run/cardano-node/node_preview.socket
BLOCKFROST_PROJECT_ID: ${{ secrets.BLOCKFROST_TESTS_PROJECT_ID }}
SUBMIT_MNEMONIC: ${{ secrets.BLOCKFROST_TESTS_SUBMIT_MNEMONIC }}
LLVM_PROFILE_FILE: ${{ github.workspace }}/hydra-pg-%p-%m.profraw
run: |
nix run -L .#internal.x86_64-linux.hydra-platform-gateway-test

- name: Convert profraw to LCOV
if: always()
run: nix run -L .#internal.x86_64-linux.coverage-convert-hydra-pg

- name: Upload coverage
if: always()
uses: actions/upload-artifact@v5
with:
name: coverage-hydra-platform-gateway
path: hydra-platform-gateway.lcov
if-no-files-found: ignore

hydra_bridge_gateway_tests:
name: Hydra micropayments tests between Bridge↔Gateway
runs-on: [self-hosted, Linux, X64, nixos]
Expand All @@ -58,5 +71,52 @@ jobs:
CARDANO_NODE_SOCKET_PATH: /run/cardano-node/node_preview.socket
BLOCKFROST_PROJECT_ID: ${{ secrets.BLOCKFROST_TESTS_PROJECT_ID }}
SUBMIT_MNEMONIC: ${{ secrets.BLOCKFROST_TESTS_SUBMIT_MNEMONIC }}
LLVM_PROFILE_FILE: ${{ github.workspace }}/hydra-bg-%p-%m.profraw
run: |
nix run -L .#internal.x86_64-linux.hydra-bridge-gateway-test

- name: Convert profraw to LCOV
if: always()
run: nix run -L .#internal.x86_64-linux.coverage-convert-hydra-bg

- name: Upload coverage
if: always()
uses: actions/upload-artifact@v5
with:
name: coverage-hydra-bridge-gateway
path: hydra-bridge-gateway.lcov
if-no-files-found: ignore

hydra_coverage_cache:
name: Cache Hydra coverage for CI
runs-on: ubuntu-latest
if: always()
needs:
- hydra_platform_gateway_tests
- hydra_bridge_gateway_tests
steps:
- name: Download Hydra coverage artifacts
uses: actions/download-artifact@v5
with:
pattern: coverage-hydra-*
merge-multiple: true

- name: Install lcov
run: sudo apt-get install -y lcov

- name: Merge Hydra LCOVs
run: |
args=()
for f in hydra-*.lcov; do
[ -f "$f" ] && args+=(-a "$f")
done
if [ ${#args[@]} -gt 0 ]; then
lcov "${args[@]}" -o hydra-combined.lcov
fi

- name: Save to cache
if: hashFiles('hydra-combined.lcov') != ''
uses: actions/cache/save@v4
with:
path: hydra-combined.lcov
key: hydra-coverage-${{ github.run_id }}
9 changes: 4 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ result-*

*.log

# Ignore coverage files
build_rs_cov.profraw
cobertura.xml
tarpaulin-report.html
coverage
# Coverage artifacts (LLVM source-based coverage)
*.profraw
*.profdata
coverage-html/
3 changes: 0 additions & 3 deletions crates/error_decoder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ hex.workspace = true
serde_json.workspace = true
tokio.workspace = true

[features]
tarpaulin = []

[build-dependencies]
bf-build-utils.workspace = true

Expand Down
6 changes: 2 additions & 4 deletions crates/error_decoder/src/external.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ impl ExternalDecoder {
}

/// A single global [`ExternalDecoder`] that you can cheaply use in tests.
#[cfg(all(test, not(feature = "tarpaulin")))]
#[cfg(test)]
pub fn instance() -> Self {
GLOBAL_INSTANCE.clone()
}
}

#[cfg(all(test, not(feature = "tarpaulin")))]
#[cfg(test)]
static GLOBAL_INSTANCE: std::sync::LazyLock<ExternalDecoder> =
std::sync::LazyLock::new(|| ExternalDecoder::spawn().expect("Failed to spawn ExternalDecoder"));

Expand All @@ -70,12 +70,10 @@ mod tests {
// which already cross-validates the Rust (pallas-hardano) implementation against the
// Haskell (testgen-hs) external decoder. This module only contains tests that are
// unique to the external decoder itself (e.g. crash-recovery behaviour).
#[cfg(not(feature = "tarpaulin"))]
use super::*;

#[tokio::test]
//#[tracing_test::traced_test]
#[cfg(not(feature = "tarpaulin"))]
async fn test_sanity() {
let decoder = ExternalDecoder::spawn().unwrap();

Expand Down
2 changes: 0 additions & 2 deletions crates/error_decoder/src/tests/random.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![cfg(not(feature = "tarpaulin"))]

use bf_testgen::tests::{CaseType, check_generated_cases};
use pallas_hardano::display::haskell_error::serialize_error;
use pallas_network::miniprotocols::localtxsubmission::TxValidationError;
Expand Down
15 changes: 2 additions & 13 deletions crates/error_decoder/src/tests/specific.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ use pallas_network::miniprotocols::localtxsubmission::TxValidationError;

/// This function takes a CBOR-encoded `ApplyTxErr`, and verifies our
/// deserializer against the Haskell one. Use it for specific cases.
///
/// Under `tarpaulin`, the external Haskell decoder (`testgen-hs`) is not
/// available, so we only exercise the Rust decode + serialize path (which is
/// what we want coverage for anyway).
#[cfg(test)]
pub(crate) async fn verify_one(cbor: &str) {
use pallas_hardano::display::haskell_error::serialize_error;
Expand All @@ -36,7 +32,6 @@ pub(crate) async fn verify_one(cbor: &str) {
let our_decoding = decode_error(&cbor);
let our_json = serialize_error(our_decoding).expect("Failed to serialize error");

#[cfg(not(feature = "tarpaulin"))]
{
use crate::external::ExternalDecoder;

Expand All @@ -57,12 +52,6 @@ pub(crate) async fn verify_one(cbor: &str) {

assert_json_eq!(reference_json, our_json);
}

// Under tarpaulin: just assert the Rust decoder didn't panic and produced valid JSON.
#[cfg(feature = "tarpaulin")]
{
let _ = our_json;
}
}
#[cfg(test)]
fn decode_error(bytes: &[u8]) -> TxValidationError {
Expand All @@ -72,7 +61,7 @@ fn decode_error(bytes: &[u8]) -> TxValidationError {
decoder.decode().unwrap()
}

#[cfg(all(test, not(feature = "tarpaulin")))]
#[cfg(test)]
macro_rules! assert_json_eq {
($left:expr, $right:expr) => {
if $left != $right {
Expand All @@ -90,7 +79,7 @@ macro_rules! assert_json_eq {
};
}

#[cfg(all(test, not(feature = "tarpaulin")))]
#[cfg(test)]
pub(crate) use assert_json_eq; // export it

#[tokio::test]
Expand Down
3 changes: 0 additions & 3 deletions crates/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,5 @@ chrono.workspace = true
[build-dependencies]
bf-build-utils.workspace = true

[features]
tarpaulin = []

[lints]
workspace = true
1 change: 0 additions & 1 deletion crates/testgen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,4 @@ num_cpus.workspace = true
crossbeam.workspace = true

[features]
tarpaulin = []
test-utils = []
1 change: 0 additions & 1 deletion nix/devshells.nix
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ in {
{package = internal.hydra-node;}
{package = internal.dolos;}
{package = pkgs.cargo-nextest;}
{package = pkgs.cargo-tarpaulin;}
{
name = "cargo";
package = internal.rustPackages.cargo;
Expand Down
Loading
Loading