docs(plan): drop the launchd integration test
Task 6 is documentation-only. A real launchd cycle test would either hard-code the live label and risk clobbering a working installation, or need a test-only --label flag; the manual acceptance section covers the mechanism instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EGntTHCW3sEPy1VBRopNNp
This commit is contained in:
@@ -38,9 +38,14 @@
|
||||
| `crates/xy/src/cli/mod.rs` | *Modify:* declare `mod service;` and re-export |
|
||||
| `crates/xy/src/main.rs` | *Modify:* `Service` subcommand arm; reorder path resolution before logger init |
|
||||
| `crates/xy/src/daemon/mod.rs` | *Modify:* drop the now-duplicated `ensure_dirs()` call |
|
||||
| `crates/xy/tests/service.rs` | *New:* `#[ignore]` end-to-end launchd cycle |
|
||||
| `README.md` | *Modify:* document the five verbs |
|
||||
|
||||
No integration test is planned. Driving a real launchd cycle would either
|
||||
hard-code the live `se.aceofba.xy` label and risk clobbering a working
|
||||
installation, or require a test-only `--label` flag on the CLI. The load/unload
|
||||
mechanism is covered instead by the *Manual acceptance* section at the end of
|
||||
this plan, which is the only check that can actually prove `RunAtLoad` works.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: `io::Write` for `RotatingLogWriter`
|
||||
@@ -1161,82 +1166,21 @@ git commit -m "feat(cli): xy service install/uninstall/start/stop/status"
|
||||
|
||||
---
|
||||
|
||||
### Task 6: End-to-end test and documentation
|
||||
### Task 6: Documentation
|
||||
|
||||
An ignored integration test that exercises a real launchd cycle under a distinct label, plus README coverage.
|
||||
Document the five verbs in the README. No integration test: driving a real
|
||||
launchd cycle would either hard-code the live `se.aceofba.xy` label and risk
|
||||
clobbering a working installation, or require a test-only `--label` flag on the
|
||||
CLI. The *Manual acceptance* section below covers the mechanism instead.
|
||||
|
||||
**Files:**
|
||||
- Create: `crates/xy/tests/service.rs`
|
||||
- Modify: `README.md`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: the `xy` binary built by cargo. The test shells out rather than linking, because `service.rs` is `pub(crate)`.
|
||||
- Consumes: nothing from earlier tasks.
|
||||
- Produces: nothing consumed by later tasks.
|
||||
|
||||
- [ ] **Step 1: Write the ignored end-to-end test**
|
||||
|
||||
Create `crates/xy/tests/service.rs`:
|
||||
|
||||
```rust
|
||||
use std::process::Command;
|
||||
|
||||
fn launchctl(verb: &str, arg: &str) -> bool {
|
||||
Command::new("launchctl")
|
||||
.arg(verb)
|
||||
.arg(arg)
|
||||
.output()
|
||||
.map(|out| out.status.success())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "installs a real launchd agent; run manually with --ignored"]
|
||||
fn install_start_stop_uninstall_cycle() {
|
||||
let home = std::env::var("HOME").unwrap();
|
||||
let plist = format!("{home}/Library/LaunchAgents/se.aceofba.xy-test.plist");
|
||||
|
||||
assert!(
|
||||
!std::path::Path::new(&plist).exists(),
|
||||
"test agent already installed; remove {plist} first"
|
||||
);
|
||||
|
||||
let contents = format!(
|
||||
r#"<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0"><dict>
|
||||
<key>Label</key><string>se.aceofba.xy-test</string>
|
||||
<key>ProgramArguments</key><array><string>/bin/sleep</string><string>3600</string></array>
|
||||
<key>RunAtLoad</key><true/>
|
||||
</dict></plist>
|
||||
"#
|
||||
);
|
||||
|
||||
std::fs::write(&plist, contents).unwrap();
|
||||
|
||||
assert!(launchctl("load", &plist), "load failed");
|
||||
assert!(launchctl("unload", &plist), "unload failed");
|
||||
|
||||
std::fs::remove_file(&plist).unwrap();
|
||||
|
||||
assert!(!std::path::Path::new(&plist).exists());
|
||||
}
|
||||
```
|
||||
|
||||
This deliberately drives `launchctl` against a harmless `/bin/sleep` agent under the `se.aceofba.xy-test` label rather than invoking `xy service install`, which would hard-code the real `se.aceofba.xy` label and could disturb a working installation. It verifies the load/unload mechanism Task 4 relies on.
|
||||
|
||||
- [ ] **Step 2: Confirm it is skipped by default**
|
||||
|
||||
Run: `cargo nextest run -p xy`
|
||||
|
||||
Expected: the test is listed as skipped, not run.
|
||||
|
||||
- [ ] **Step 3: Run it explicitly and confirm it passes**
|
||||
|
||||
Run: `cargo nextest run -p xy --run-ignored all -E 'test(/install_start_stop_uninstall_cycle/)'`
|
||||
|
||||
Expected: PASS. Then confirm no residue: `ls ~/Library/LaunchAgents/ | grep xy-test` returns nothing.
|
||||
|
||||
- [ ] **Step 4: Document the feature**
|
||||
- [ ] **Step 1: Document the feature**
|
||||
|
||||
Add to `README.md`, after the existing command list:
|
||||
|
||||
@@ -1264,7 +1208,7 @@ visible only to launchd:
|
||||
launchctl print gui/$UID/se.aceofba.xy
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Full suite, format, lint**
|
||||
- [ ] **Step 2: Full suite, format, lint**
|
||||
|
||||
```bash
|
||||
cargo nextest run
|
||||
@@ -1272,11 +1216,11 @@ cargo +nightly fmt
|
||||
cargo clippy --workspace
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add crates/xy/tests/service.rs README.md
|
||||
git commit -m "test(service): ignored launchd cycle test; document xy service"
|
||||
git add README.md
|
||||
git commit -m "docs(readme): document xy service verbs"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user