diff --git a/.github/workflows/container-e2e.yml b/.github/workflows/container-e2e.yml index 7f8d5ef2..a4780a9c 100644 --- a/.github/workflows/container-e2e.yml +++ b/.github/workflows/container-e2e.yml @@ -127,6 +127,7 @@ jobs: env: E2E_CONTAINER_IMAGE: ghcr.io/swananan/ghostscope-e2e-runtime@sha256:d5df1b977c38f7a51bbf28b878f2246705a05b83ac6df7cb6be8f8a4de4105f4 E2E_CHILD_CONTAINER_IMAGE: ghcr.io/swananan/ghostscope-e2e-runtime@sha256:d5df1b977c38f7a51bbf28b878f2246705a05b83ac6df7cb6be8f8a4de4105f4 + E2E_RUN_CONTAINER_TOPOLOGY: 1 E2E_SANDBOX_SESSION: container-e2e-${{ github.run_id }}-${{ github.job }}-${{ matrix.name }} E2E_GHOSTSCOPE_SANDBOX: ${{ matrix.ghostscope_sandbox }} E2E_TARGET_SANDBOX: ${{ matrix.target_sandbox }} @@ -136,6 +137,7 @@ jobs: sudo -E env \ E2E_CONTAINER_IMAGE="$E2E_CONTAINER_IMAGE" \ E2E_CHILD_CONTAINER_IMAGE="$E2E_CHILD_CONTAINER_IMAGE" \ + E2E_RUN_CONTAINER_TOPOLOGY="$E2E_RUN_CONTAINER_TOPOLOGY" \ E2E_SANDBOX_SESSION="$E2E_SANDBOX_SESSION" \ E2E_GHOSTSCOPE_SANDBOX="$E2E_GHOSTSCOPE_SANDBOX" \ E2E_TARGET_SANDBOX="$E2E_TARGET_SANDBOX" \ diff --git a/docs/development.md b/docs/development.md index 5d9de07e..a55b822d 100644 --- a/docs/development.md +++ b/docs/development.md @@ -209,6 +209,8 @@ Test-framework environment variables: - `E2E_TARGET_MODE=same|child-container` Refines how the target is launched inside the selected target sandbox. Default: `same`. `child-container` currently means "launch the target in a nested child container inside the outer `docker-private` sandbox". +- `E2E_RUN_CONTAINER_TOPOLOGY=1` + Enables the explicit `container_topology_execution` tests. These tests are skipped in routine host-host e2e runs unless this flag is set or a docker-backed `E2E_GHOSTSCOPE_SANDBOX`/`E2E_TARGET_SANDBOX`/`E2E_TARGET_MODE` is requested. - `E2E_CHILD_CONTAINER_IMAGE=` Overrides the image used for nested `child-container` targets. By default it inherits `E2E_CONTAINER_IMAGE`, so the outer sandbox and nested child container use the same runtime image unless you explicitly split them. - `E2E_GHOSTSCOPE_LOG_LEVEL=error|warn|info|debug|trace` @@ -293,7 +295,7 @@ Notes: - These commands keep the Rust test harness on the host and move GhostScope plus the traced target into the requested container sandbox topology. - When GhostScope and target use the same sandbox kind, the topology-aware e2e helper automatically reuses the same sandbox instance. -- The main `CI` workflow runs the full `ghostscope-e2e-tests` suite under the default host-host environment, including `container_topology_execution`. +- Routine host-host e2e, including the main `CI` workflow, skips the explicit `container_topology_execution` cases by default. - `host -> docker-private`, `docker-private -> same docker-private`, and `docker-private -> child-container` are the explicit topology scenarios that currently run the full e2e suite in the dedicated `Container E2E` workflow. - `docker-private -> child-container` uses `E2E_TARGET_MODE=child-container` and launches the target in a nested Docker child container inside the outer private sandbox. The full suite now runs in CI for that topology, while nested child-container `-t` cases still follow the existing explicit skip path inside the Rust tests. - `docker-host -> same docker-host` remains a smoke run because it is close to the default host PID view. diff --git a/docs/zh/development.md b/docs/zh/development.md index 515bc037..d3b17334 100644 --- a/docs/zh/development.md +++ b/docs/zh/development.md @@ -210,6 +210,8 @@ curl -sS -X POST http://127.0.0.1:8788/runs \ - `E2E_TARGET_MODE=same|child-container` 进一步描述目标进程在所选 target sandbox 里的启动方式。默认:`same`。 目前 `child-container` 专指“在外层 `docker-private` sandbox 里再起一个子容器来运行目标进程”。 +- `E2E_RUN_CONTAINER_TOPOLOGY=1` + 启用显式的 `container_topology_execution` 测试。常规 host-host e2e 默认跳过这些用例;只有设置该变量,或显式请求 docker-backed `E2E_GHOSTSCOPE_SANDBOX`/`E2E_TARGET_SANDBOX`/`E2E_TARGET_MODE` 时才会运行。 - `E2E_CHILD_CONTAINER_IMAGE=` 覆盖 nested `child-container` 目标使用的镜像。默认会继承 `E2E_CONTAINER_IMAGE`,也就是外层 sandbox 和子容器默认共用同一张 runtime 镜像,除非你显式指定不同镜像。 - `E2E_GHOSTSCOPE_LOG_LEVEL=error|warn|info|debug|trace` @@ -294,7 +296,7 @@ done - Rust 测试 harness 仍运行在宿主机上,GhostScope 和目标进程会按指定拓扑进入对应容器 sandbox。 - 当 GhostScope 和目标使用同一种 sandbox 类型时,topology-aware e2e helper 会自动复用同一个 sandbox 实例。 -- 主 `CI` workflow 会在默认 host-host 环境下跑完整的 `ghostscope-e2e-tests` 套件,其中也包括 `container_topology_execution`。 +- 常规 host-host e2e,包括主 `CI` workflow,默认跳过显式的 `container_topology_execution` 用例。 - `host -> docker-private`、`docker-private -> same docker-private` 和 `docker-private -> child-container` 是当前在独立 `Container E2E` workflow 中按显式 topology 跑全量 e2e 的容器场景。 - `docker-private -> child-container` 通过 `E2E_TARGET_MODE=child-container` 启用,表示目标进程运行在外层 private sandbox 里再启动的子容器中。这个拓扑现在已经进入 full-CI 矩阵,但 nested child-container 的 `-t` 用例在 Rust 测试内部仍然沿用现有的显式跳过路径。 - `docker-host -> same docker-host` 仍保留为 smoke,因为它更接近默认的 host PID 视角。 diff --git a/e2e-tests/README.md b/e2e-tests/README.md index fc144546..410d670c 100644 --- a/e2e-tests/README.md +++ b/e2e-tests/README.md @@ -13,3 +13,7 @@ Typical local flow: cargo build -p ghostscope -p dwarf-tool --all-features sudo cargo test -p ghostscope-e2e-tests --tests --all-features -- --nocapture ``` + +Routine host-host e2e skips the explicit container-topology cases. Run them by +setting `E2E_RUN_CONTAINER_TOPOLOGY=1` or by using one of the docker-backed +`E2E_GHOSTSCOPE_SANDBOX`/`E2E_TARGET_SANDBOX` topology settings. diff --git a/e2e-tests/tests/container_topology_execution.rs b/e2e-tests/tests/container_topology_execution.rs index 6c462758..4ee02f04 100644 --- a/e2e-tests/tests/container_topology_execution.rs +++ b/e2e-tests/tests/container_topology_execution.rs @@ -6,6 +6,11 @@ use common::sandbox::{DockerSpec, SandboxHandle}; use common::targets::{TargetHandle, TargetLauncher}; use serial_test::serial; +const ENV_RUN_CONTAINER_TOPOLOGY: &str = "E2E_RUN_CONTAINER_TOPOLOGY"; +const ENV_GHOSTSCOPE_SANDBOX: &str = "E2E_GHOSTSCOPE_SANDBOX"; +const ENV_TARGET_SANDBOX: &str = "E2E_TARGET_SANDBOX"; +const ENV_TARGET_MODE: &str = "E2E_TARGET_MODE"; + fn pid_filter_script() -> &'static str { r#" trace calculate_something { @@ -14,6 +19,54 @@ trace calculate_something { "# } +fn env_flag_enabled(name: &str) -> bool { + std::env::var(name).ok().is_some_and(|value| { + matches!( + value.trim().to_ascii_lowercase().as_str(), + "1" | "true" | "yes" | "on" + ) + }) +} + +fn env_value_is_container_sandbox(name: &str) -> bool { + std::env::var(name).ok().is_some_and(|value| { + matches!( + value.trim().to_ascii_lowercase().as_str(), + "docker-private" + | "private" + | "container-private" + | "docker-host" + | "host-pid" + | "docker-host-pid" + | "container-host" + ) + }) +} + +fn explicit_container_topology_requested() -> bool { + env_flag_enabled(ENV_RUN_CONTAINER_TOPOLOGY) + || env_value_is_container_sandbox(ENV_GHOSTSCOPE_SANDBOX) + || env_value_is_container_sandbox(ENV_TARGET_SANDBOX) + || std::env::var(ENV_TARGET_MODE).ok().is_some_and(|value| { + matches!( + value.trim().to_ascii_lowercase().as_str(), + "child-container" | "child" | "nested" | "descendant" + ) + }) +} + +fn skip_if_container_topology_not_requested() -> bool { + if explicit_container_topology_requested() { + false + } else { + eprintln!( + "skipping explicit container-topology test: set {ENV_RUN_CONTAINER_TOPOLOGY}=1 \ + or run with docker-backed E2E_GHOSTSCOPE_SANDBOX/E2E_TARGET_SANDBOX" + ); + true + } +} + fn skip_if_docker_unavailable() -> bool { if SandboxHandle::docker_available() { false @@ -69,6 +122,9 @@ fn target_diagnostics(target: &TargetHandle) -> String { #[serial] async fn test_attach_from_host_to_private_container_target() -> anyhow::Result<()> { init(); + if skip_if_container_topology_not_requested() { + return Ok(()); + } if skip_if_docker_unavailable() { return Ok(()); } @@ -108,6 +164,9 @@ async fn test_attach_from_host_to_private_container_target() -> anyhow::Result<( #[serial] async fn test_attach_from_host_pid_container_to_host_target() -> anyhow::Result<()> { init(); + if skip_if_container_topology_not_requested() { + return Ok(()); + } if skip_if_docker_unavailable() { return Ok(()); } @@ -148,6 +207,9 @@ async fn test_attach_from_host_pid_container_to_host_target() -> anyhow::Result< async fn test_attach_from_private_container_to_host_target_fails_when_pid_invisible( ) -> anyhow::Result<()> { init(); + if skip_if_container_topology_not_requested() { + return Ok(()); + } if skip_if_docker_unavailable() { return Ok(()); } @@ -183,6 +245,9 @@ async fn test_attach_from_private_container_to_host_target_fails_when_pid_invisi #[serial] async fn test_child_container_runtime_reuses_single_nested_container() -> anyhow::Result<()> { init(); + if skip_if_container_topology_not_requested() { + return Ok(()); + } if skip_if_docker_unavailable() { return Ok(()); } @@ -238,6 +303,9 @@ async fn test_child_container_runtime_reuses_single_nested_container() -> anyhow #[serial] async fn test_attach_from_private_container_to_child_container_target() -> anyhow::Result<()> { init(); + if skip_if_container_topology_not_requested() { + return Ok(()); + } if skip_if_docker_unavailable() { return Ok(()); } diff --git a/scripts/e2e/container/common.sh b/scripts/e2e/container/common.sh index 624fd553..1fd109e2 100755 --- a/scripts/e2e/container/common.sh +++ b/scripts/e2e/container/common.sh @@ -196,6 +196,7 @@ execute_topology_cargo() { E2E_SANDBOX_SESSION="$E2E_SANDBOX_SESSION" E2E_CONTAINER_IMAGE="${E2E_CONTAINER_IMAGE:-$DEFAULT_RUNTIME_IMAGE}" E2E_CHILD_CONTAINER_IMAGE="${E2E_CHILD_CONTAINER_IMAGE:-${E2E_CONTAINER_IMAGE:-$DEFAULT_RUNTIME_IMAGE}}" + E2E_RUN_CONTAINER_TOPOLOGY=1 E2E_GHOSTSCOPE_SANDBOX="$ghostscope_sandbox" E2E_TARGET_SANDBOX="$target_sandbox" E2E_TARGET_MODE="$target_mode"