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
27 changes: 27 additions & 0 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -278,12 +278,36 @@ info "-- IMAGE = ${IMAGE_NAME}"
info "-- TAG = $TAG"
# info "-- TEST_BINARIES_DIR = ${TEST_BINARIES_DIR}"

# Run podman in foreground with proper signal handling
# Set container name for cleanup. Suffix with $$ (script PID) so concurrent
# `makers container-test` invocations on the same host don't collide on the
# `zaino-testing` name. The base-script cleanup trap reads CONTAINER_NAME
# from script scope and stops the right container on EXIT/INT/TERM.
CONTAINER_NAME="zaino-testing-$$"

# Capture git info on the host and forward it into the container so the
# build script does not need to shell out to git from within the bind
# mount. In a worktree the bind-mounted .git is a file pointing to a
# host-only path, so an in-container `git rev-parse` returns empty and
# (worse) a missing-path `cargo:rerun-if-changed` invalidates every
# build. Reading these from env vars keeps the container build
# deterministic across runs.
GIT_COMMIT="$(git rev-parse HEAD 2>/dev/null || echo unknown)"
BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)"

# Conditionally mount a local infras checkout if one exists at the
# expected sibling path. integration-tests/Cargo.toml may carry
# path-based deps like `../../../infras/dev/zcash_local_net` that only
# resolve when this directory is present inside the container at the
# matching location. If the host doesn't have an infras checkout the
# mount is skipped and any path-dep error surfaces as it would today.
EXTRA_MOUNTS=()
if [[ -d "$PWD/../../infras/dev" ]]; then
INFRAS_HOST_PATH="$(cd "$PWD/../../infras/dev" && pwd -P)"
info "-- INFRAS_MOUNT = ${INFRAS_HOST_PATH} -> /home/infras/dev"
EXTRA_MOUNTS+=(-v "${INFRAS_HOST_PATH}:/home/infras/dev")
fi

# Run podman in foreground with proper signal handling.
#
# `--pids-limit=-1` removes the default 2048-process cgroup cap. With
Expand All @@ -301,10 +325,13 @@ podman run --rm \
-v zaino-container-target:/home/container_user/zaino/target:U \
-v zaino-cargo-git:/usr/local/cargo/git:U \
-v zaino-cargo-registry:/usr/local/cargo/registry:U \
${EXTRA_MOUNTS[@]+"${EXTRA_MOUNTS[@]}"} \
-e "TEST_BINARIES_DIR=${TEST_BINARIES_DIR}" \
-e "NEXTEST_EXPERIMENTAL_LIBTEST_JSON=1" \
-e "ZAINOLOG_FORMAT=${ZAINOLOG_FORMAT:-stream}" \
-e "RUST_LOG=${RUST_LOG:-}" \
-e "GIT_COMMIT=${GIT_COMMIT}" \
-e "BRANCH=${BRANCH}" \
-w /home/container_user/zaino \
-u container_user \
"${IMAGE_NAME}:$TAG" \
Expand Down
1 change: 0 additions & 1 deletion integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ corez = "0.1"
futures = "0.3.30"
hex = "0.4"
once_cell = "1.20"
portpicker = "0.1"
serde_json = "1.0"
tempfile = "3.2"
tracing = "0.1"
Expand Down
1 change: 0 additions & 1 deletion integration-tests/zaino-testutils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ zingolib_testutils.workspace = true
# Miscellaneous
http = { workspace = true }
once_cell = { workspace = true }
portpicker = { workspace = true }
tokio = { workspace = true }
tonic.workspace = true
tempfile = { workspace = true }
Expand Down
17 changes: 14 additions & 3 deletions integration-tests/zaino-testutils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use zcash_local_net::{
error::LaunchError,
validator::zcashd::{Zcashd, ZcashdConfig},
};
use zcash_local_net::network::pick_unused_port;
use zcash_local_net::{logs::LogsToStdoutAndStderr, process::Process};
use zebra_chain::parameters::NetworkKind;
#[cfg(test)]
Expand All @@ -58,7 +59,7 @@ fn binary_path(binary_name: &str) -> Option<PathBuf> {
}

/// Create local URI from port.
pub fn make_uri(indexer_port: portpicker::Port) -> http::Uri {
pub fn make_uri(indexer_port: u16) -> http::Uri {
format!("http://127.0.0.1:{indexer_port}")
.try_into()
.unwrap()
Expand Down Expand Up @@ -453,10 +454,20 @@ where
zaino_json_listen_address,
zaino_json_server_cookie_dir,
) = if enable_zaino {
let zaino_grpc_listen_port = portpicker::pick_unused_port().expect("No ports free");
// Was `portpicker::pick_unused_port()` — that helper samples
// randomly from `15000..25000` and bind-checks, a 10 000-port
// range that suffers measurable birthday-paradox collisions
// when many test subprocesses run in parallel (the in-the-wild
// `ConnectionRefused` flakes on `zebrad::get::*`,
// `zebra::lightwallet_indexer::*`, etc., all reproduce here).
// `zcash_local_net::network::pick_unused_port` lets the kernel
// assign an ephemeral instead — sequential allocation in the
// 32768+ range, TIME_WAIT-cooled, effectively zero-collision
// even across test subprocesses.
let zaino_grpc_listen_port = pick_unused_port(None);
let zaino_grpc_listen_address =
SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), zaino_grpc_listen_port);
let zaino_json_listen_port = portpicker::pick_unused_port().expect("No ports free");
let zaino_json_listen_port = pick_unused_port(None);
let zaino_json_listen_address =
SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), zaino_json_listen_port);
debug!(
Expand Down
55 changes: 49 additions & 6 deletions packages/zaino-state/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,62 @@ fn git(args: &[&str]) -> String {
.to_string()
}

/// `git rev-parse --git-path <path>` — resolves a name inside the gitdir
/// to its on-disk location, transparently handling worktrees (where the
/// gitdir lives under `<main>/.git/worktrees/<name>/`). Returns `None`
/// when git can't resolve the repository at all (e.g. a workspace bind-
/// mounted into a container with no access to the host gitdir).
fn git_path(name: &str) -> Option<String> {
let out = Command::new("git")
.args(["rev-parse", "--git-path", name])
.output()
.ok()?;
if !out.status.success() {
return None;
}
let path = String::from_utf8(out.stdout).ok()?.trim().to_string();
(!path.is_empty()).then_some(path)
}

fn main() -> io::Result<()> {
// Without these, cargo's default is "rerun if any file in the package
// changes", which combined with wall-clock-derived rustc-env values
// would invalidate this crate (and everything downstream) on every build.
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=../../.git/HEAD");
// Resolve HEAD's actual path at build time. In a regular clone this is
// `.git/HEAD`; in a worktree `.git` is a file, not a directory, and
// HEAD lives at `<main>/.git/worktrees/<name>/HEAD`. Hardcoding
// `../../.git/HEAD` is fine for regular clones but resolves to a
// missing path under a worktree, which cargo treats as
// always-changed — forcing this crate (and everything downstream) to
// recompile on every build. `git rev-parse --git-path HEAD` returns
// the right path in both cases. If git can't resolve the repo at all
// (e.g. the workspace bind-mounted into a container can't reach the
// host gitdir), skip the directive — `cargo:rerun-if-env-changed=…`
// above already covers the in-container invalidation story.
if let Some(head_path) = git_path("HEAD") {
println!("cargo:rerun-if-changed={head_path}");
}
println!("cargo:rerun-if-env-changed=SOURCE_DATE_EPOCH");
println!("cargo:rerun-if-env-changed=GIT_COMMIT");
println!("cargo:rerun-if-env-changed=BRANCH");

// Prefer caller-supplied values: the makers container-test task computes
// these on the host and passes them via `-e`, so the in-container build
// does not depend on a working git inside the bind-mounted workspace
// (which is broken across worktree gitdir indirection). Fall back to
// shelling out for direct host invocations of `cargo build`.
let git_commit = env::var("GIT_COMMIT")
.ok()
.filter(|s| !s.is_empty())
.unwrap_or_else(|| git(&["rev-parse", "HEAD"]));
println!("cargo:rustc-env=GIT_COMMIT={git_commit}");

println!("cargo:rustc-env=GIT_COMMIT={}", git(&["rev-parse", "HEAD"]));
println!(
"cargo:rustc-env=BRANCH={}",
git(&["rev-parse", "--abbrev-ref", "HEAD"])
);
let branch = env::var("BRANCH")
.ok()
.filter(|s| !s.is_empty())
.unwrap_or_else(|| git(&["rev-parse", "--abbrev-ref", "HEAD"]));
println!("cargo:rustc-env=BRANCH={branch}");

// BUILD_DATE: SOURCE_DATE_EPOCH if set
// (https://reproducible-builds.org/docs/source-date-epoch/), otherwise
Expand Down
Loading