Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .github/workflows/container-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand All @@ -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" \
Expand Down
4 changes: 3 additions & 1 deletion docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -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=<image-ref>`
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`
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 3 additions & 1 deletion docs/zh/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -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=<image-ref>`
覆盖 nested `child-container` 目标使用的镜像。默认会继承 `E2E_CONTAINER_IMAGE`,也就是外层 sandbox 和子容器默认共用同一张 runtime 镜像,除非你显式指定不同镜像。
- `E2E_GHOSTSCOPE_LOG_LEVEL=error|warn|info|debug|trace`
Expand Down Expand Up @@ -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 视角。
Expand Down
4 changes: 4 additions & 0 deletions e2e-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
68 changes: 68 additions & 0 deletions e2e-tests/tests/container_topology_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -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(());
}
Expand Down Expand Up @@ -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(());
}
Expand Down Expand Up @@ -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(());
}
Expand Down Expand Up @@ -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(());
}
Expand Down Expand Up @@ -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(());
}
Expand Down
1 change: 1 addition & 0 deletions scripts/e2e/container/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading