Skip to content
Open
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
691 changes: 691 additions & 0 deletions docs/design/drive9-agent-harness-v2-plan.md

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions e2e/agent-harness/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
title: Drive9 Agent Harness
---

## Commands

1. Build:

```bash
go build ./e2e/agent-harness/cmd/drive9-agent-harness
```

2. Preflight:

```bash
drive9-agent-harness preflight --api-key "$DRIVE9_API_KEY"
```

3. Smoke:

```bash
drive9-agent-harness run --suite smoke --api-key "$DRIVE9_API_KEY"
```

4. Targeted regression:

```bash
drive9-agent-harness run --suite regression --case path-edge-strict,git-lock-strict,doctor-no-allow-other --api-key "$DRIVE9_API_KEY"
```

5. Stress:

```bash
drive9-agent-harness run --suite stress --api-key "$DRIVE9_API_KEY"
```

6. Fault injection:

```bash
drive9-agent-harness run --suite fault --allow-fault --api-key "$DRIVE9_API_KEY"
```

7. Regenerate report:

```bash
drive9-agent-harness report --run-dir /tmp/drive9-agent-test-YYYYMMDDTHHMMSSZ
```

8. Garbage collect generated local mountpoints and remote roots:

```bash
drive9-agent-harness gc --run-dir /tmp/drive9-agent-test-YYYYMMDDTHHMMSSZ --confirm-delete
```

9. Collect server evidence:

```bash
drive9-agent-harness collect-server-evidence --run-dir /tmp/drive9-agent-test-YYYYMMDDTHHMMSSZ --approve-external --kube-context prod-dat9-eks-ap-southeast-1
```

## Phase 1 Contract

1. Each case gets a generated remote root under `--remote-root-base`.
2. The harness creates the remote root with `drive9 fs mkdir` before mounting.
3. The mount source is exactly the generated case root.
4. Known-bug cases keep correct-behavior oracles. Failing product oracles are non-gating and passing product oracles become fixed candidates.
5. Remote-root deletion is deferred. Local mountpoints are removed only for `cleanup: always` after verified unmount.

## Extended Harness

1. `stress.yaml` covers sequential `fio`, small-file storm, and parallel writer workloads.
2. `fault.yaml` covers open-file unmount and kill-during-write recovery classification.
3. `gc` refuses to delete without `--confirm-delete` and checks run gating when `--successful-only` is set.
4. `collect-server-evidence` refuses external reads without `--approve-external`.
38 changes: 38 additions & 0 deletions e2e/agent-harness/cases/fault.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
defaults:
timeout: 5m
cleanup: retain_on_failure
mount_ready_timeout: 20s
remote_visibility_timeout: 30s
command_retry_count: 8
command_retry_sleep: 2s
requires_fresh_tenant: false
cases:
- id: open-fd-unmount-strict
suite: fault
sync_mode: strict
expected_outcome: baseline_pass
remote_root_suffix: open-fd-unmount-strict
mountpoint_suffix: open-fd-unmount-strict
workload:
type: open_fd_unmount
hold_open_duration: 1s
remount: false
oracles:
- type: unmount_busy_then_clean
severity:
failure: P2
- id: kill-during-write-strict
suite: fault
sync_mode: strict
expected_outcome: baseline_pass
remote_root_suffix: kill-during-write-strict
mountpoint_suffix: kill-during-write-strict
workload:
type: kill_during_write
writer_bytes: 67108864
kill_after: 500ms
remount: false
oracles:
- type: recovery_classified
severity:
failure: P2
133 changes: 133 additions & 0 deletions e2e/agent-harness/cases/regression.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
defaults:
timeout: 2m
cleanup: retain_on_failure
mount_ready_timeout: 20s
remote_visibility_timeout: 5s
command_retry_count: 8
command_retry_sleep: 2s
requires_fresh_tenant: false
cases:
- id: path-edge-strict
suite: regression
sync_mode: strict
expected_outcome: bug_reproduced
remote_root_suffix: path-edge-strict
mountpoint_suffix: path-edge-strict
workload:
type: path_matrix
paths:
- "space name unicode-测试 punct_!@%.txt"
oracles:
- type: fuse_write_success
- type: cli_read_equals
- type: remount_hash_equal
severity:
failure: P1
- id: path-edge-interactive
suite: regression
sync_mode: interactive
expected_outcome: bug_reproduced
remote_root_suffix: path-edge-interactive
mountpoint_suffix: path-edge-interactive
workload:
type: path_matrix
paths:
- "space name unicode-测试 punct_!@%.txt"
oracles:
- type: fuse_write_success
- type: cli_read_equals
- type: remount_hash_equal
severity:
failure: P1
- id: git-lock-strict
suite: regression
sync_mode: strict
expected_outcome: bug_reproduced
remote_root_suffix: git-lock-strict
mountpoint_suffix: git-lock-strict
timeout: 3m
workload:
type: git_workflow
clone_url: fixture://basic
clone_dir: repo
mutation:
path: README.md
mode: append
content: |

strict git workflow mutation
commit_message: drive9 harness mutation
expected_locks: []
expected_status: ""
expected_commit_delta: 1
remount_verify_paths:
- path: README.md
oracles:
- type: no_git_locks
- type: git_status_equals
- type: git_commit_count
- type: remount_hash_equal
severity:
failure: P1
- id: git-lock-interactive
suite: regression
sync_mode: interactive
expected_outcome: bug_reproduced
remote_root_suffix: git-lock-interactive
mountpoint_suffix: git-lock-interactive
timeout: 3m
workload:
type: git_workflow
clone_url: fixture://basic
clone_dir: repo
mutation:
path: README.md
mode: append
content: |

interactive git workflow mutation
commit_message: drive9 harness mutation
expected_locks: []
expected_status: ""
expected_commit_delta: 1
remount_verify_paths:
- path: README.md
oracles:
- type: no_git_locks
- type: git_status_equals
- type: git_commit_count
- type: remount_hash_equal
severity:
failure: P1
- id: doctor-no-allow-other
suite: regression
expected_outcome: bug_reproduced
remote_root_suffix: doctor-no-allow-other
mountpoint_suffix: doctor-no-allow-other
workload:
type: doctor_fuse
expect_exit: 0
allow_nonzero_when_no_allow_other: false
oracles:
- type: command_exit
severity:
failure: P2
- id: dual-mount-visibility
suite: regression
sync_mode: interactive
expected_outcome: baseline_pass
remote_root_suffix: dual-mount-visibility
mountpoint_suffix: dual-mount-visibility
workload:
type: dual_mount_visibility
remount: true
files:
- relative_path: a-to-b.txt
content: dual mount a to b
- relative_path: b-to-a.txt
content: dual mount b to a
oracles:
- type: dual_mount_visibility
- type: remount_hash_equal
severity:
failure: P1
49 changes: 49 additions & 0 deletions e2e/agent-harness/cases/smoke.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
defaults:
timeout: 2m
cleanup: always
mount_ready_timeout: 20s
remote_visibility_timeout: 5s
command_retry_count: 8
command_retry_sleep: 2s
requires_fresh_tenant: false
cases:
- id: smoke-strict
suite: smoke
sync_mode: strict
expected_outcome: baseline_pass
remote_root_suffix: smoke-strict
mountpoint_suffix: smoke-strict
workload:
type: mount_smoke
remount: true
files:
- relative_path: cli-to-fuse.txt
content: smoke cli to fuse
- relative_path: fuse-to-cli.txt
content: smoke fuse to cli
oracles:
- type: cli_read_equals
- type: fuse_write_success
- type: remount_hash_equal
severity:
failure: P1
- id: smoke-interactive
suite: smoke
sync_mode: interactive
expected_outcome: baseline_pass
remote_root_suffix: smoke-interactive
mountpoint_suffix: smoke-interactive
workload:
type: mount_smoke
remount: true
files:
- relative_path: cli-to-fuse.txt
content: smoke interactive cli to fuse
- relative_path: fuse-to-cli.txt
content: smoke interactive fuse to cli
oracles:
- type: cli_read_equals
- type: fuse_write_success
- type: remount_hash_equal
severity:
failure: P1
60 changes: 60 additions & 0 deletions e2e/agent-harness/cases/stress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
defaults:
timeout: 20m
cleanup: retain_on_failure
mount_ready_timeout: 20s
remote_visibility_timeout: 30s
command_retry_count: 8
command_retry_sleep: 2s
requires_fresh_tenant: false
cases:
- id: fio-seq-1g-strict
suite: stress
sync_mode: strict
expected_outcome: baseline_pass
remote_root_suffix: fio-seq-1g-strict
mountpoint_suffix: fio-seq-1g-strict
workload:
type: fio
size_bytes: 1073741824
block_bytes: 1048576
min_bytes_per_second: 1
remount: false
oracles:
- type: throughput_min
severity:
failure: P2
- id: small-file-storm-interactive
suite: stress
sync_mode: interactive
expected_outcome: baseline_pass
remote_root_suffix: small-file-storm-interactive
mountpoint_suffix: small-file-storm-interactive
workload:
type: small_file_storm
file_count: 1000
read_sample_count: 20
remount: true
oracles:
- type: file_count_equals
- type: cli_read_equals
- type: remount_hash_equal
severity:
failure: P2
- id: parallel-writers-strict
suite: stress
sync_mode: strict
expected_outcome: baseline_pass
remote_root_suffix: parallel-writers-strict
mountpoint_suffix: parallel-writers-strict
workload:
type: parallel_writes
parallel_writers: 8
writer_bytes: 67108864
min_bytes_per_second: 1
remount: true
oracles:
- type: fuse_write_success
- type: throughput_min
- type: remount_hash_equal
severity:
failure: P2
Loading