Skip to content

Commit f380081

Browse files
committed
Refactor local tests for rules, opencode, and trae with isolated fixtures
- Introduced `IsolatedRulesFixture`, `IsolatedOpencodeFixture`, and `IsolatedTraeFixture` to encapsulate test setup and environment management for rules, opencode, and trae tests. - Updated tests to use the new fixture structures, improving isolation and reducing dependencies on the host workspace. - Enhanced the `write_rules_config`, `write_opencode_config`, and `write_trae_config` functions to streamline the creation of necessary configuration files for each test. - Improved assertions in the tests to ensure clarity and correctness, including checks for file existence and content validation. - Removed redundant code and comments, ensuring a cleaner and more maintainable test suite.
1 parent 87b723e commit f380081

13 files changed

Lines changed: 2801 additions & 1688 deletions

cli/local-tests/tests/agents_md_smoke.rs

Lines changed: 181 additions & 193 deletions
Large diffs are not rendered by default.

cli/local-tests/tests/claude_smoke.rs

Lines changed: 248 additions & 116 deletions
Large diffs are not rendered by default.

cli/local-tests/tests/clean_blackbox.rs

Lines changed: 236 additions & 149 deletions
Large diffs are not rendered by default.

cli/local-tests/tests/codex_smoke.rs

Lines changed: 443 additions & 291 deletions
Large diffs are not rendered by default.

cli/local-tests/tests/install_smoke.rs

Lines changed: 300 additions & 209 deletions
Large diffs are not rendered by default.

cli/local-tests/tests/logging_clean.rs

Lines changed: 116 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,128 @@
1-
//! Clean 可观测性测试:验证 clean 命令输出足够的可观测信息。
1+
//! Clean observability tests for isolated local fixtures.
2+
3+
use std::fs;
4+
use std::path::PathBuf;
25

36
use tnmsc_local_tests::LocalTestRunner;
47

8+
struct IsolatedLoggingCleanFixture {
9+
runner: LocalTestRunner,
10+
temp_home: PathBuf,
11+
project_dir: PathBuf,
12+
}
13+
14+
impl IsolatedLoggingCleanFixture {
15+
fn new() -> Self {
16+
let temp_root = std::env::temp_dir().join(format!(
17+
"tnmsc-local-logging-clean-{}-{}",
18+
std::process::id(),
19+
std::time::SystemTime::now()
20+
.duration_since(std::time::UNIX_EPOCH)
21+
.unwrap_or_default()
22+
.as_nanos()
23+
));
24+
let temp_home = temp_root.join("home");
25+
let workspace_dir = temp_root.join("workspace");
26+
let project_dir = workspace_dir.join("memory-sync");
27+
let aindex_project_dir = workspace_dir.join("aindex").join("app").join("memory-sync");
28+
29+
fs::create_dir_all(temp_home.join(".aindex")).unwrap();
30+
fs::create_dir_all(project_dir.join(".github")).unwrap();
31+
fs::create_dir_all(aindex_project_dir.join(".github")).unwrap();
32+
33+
// issue local-tests-logging-clean-isolation: logging assertions should not
34+
// depend on a host install that fails on protected workspace roots.
35+
fs::write(
36+
temp_home.join(".aindex").join(".tnmsc.json"),
37+
serde_json::json!({
38+
"workspaceDir": workspace_dir.to_string_lossy(),
39+
"plugins": {
40+
"agentsMd": false,
41+
"git": false,
42+
"readme": false,
43+
"vscode": false,
44+
"zed": false,
45+
"jetbrains": false,
46+
"jetbrainsCodeStyle": false,
47+
"claudeCode": true,
48+
"codex": false,
49+
"cursor": false,
50+
"droid": false,
51+
"gemini": false,
52+
"kiro": false,
53+
"opencode": false,
54+
"qoder": false,
55+
"trae": false,
56+
"traeCn": false,
57+
"warp": false,
58+
"windsurf": false
59+
}
60+
})
61+
.to_string(),
62+
)
63+
.unwrap();
64+
fs::write(
65+
workspace_dir.join("aindex").join("global.mdx"),
66+
"# Global memory\n\nGlobal instructions\n",
67+
)
68+
.unwrap();
69+
fs::write(
70+
workspace_dir.join("aindex").join("workspace.mdx"),
71+
"# Workspace memory\n\nWorkspace instructions\n",
72+
)
73+
.unwrap();
74+
fs::write(
75+
workspace_dir.join("aindex").join("workspace.src.mdx"),
76+
"# Workspace memory\n\nWorkspace instructions\n",
77+
)
78+
.unwrap();
79+
fs::write(
80+
aindex_project_dir.join("agt.mdx"),
81+
"# Claude project root\n\nProject root instructions\n",
82+
)
83+
.unwrap();
84+
fs::write(
85+
aindex_project_dir.join(".github").join("agt.mdx"),
86+
"# Claude child\n\nChild instructions\n",
87+
)
88+
.unwrap();
89+
90+
Self {
91+
runner: LocalTestRunner::with_cwd(&project_dir),
92+
temp_home,
93+
project_dir,
94+
}
95+
}
96+
97+
fn run(&self, args: &[&str]) -> tnmsc_local_tests::CommandResult {
98+
let temp_home = self.temp_home.to_string_lossy().into_owned();
99+
self
100+
.runner
101+
.run_at_with_env(&self.project_dir, args, &[("HOME", &temp_home)])
102+
}
103+
104+
fn install(&self) -> tnmsc_local_tests::CommandResult {
105+
self.run(&["install"])
106+
}
107+
}
108+
5109
/// Verify that `--trace` clean outputs all major spans:
6110
/// cleanup.discover and cleanup.execute.
7111
#[test]
8112
fn clean_outputs_key_spans_and_events() {
9-
let runner = LocalTestRunner::new();
10-
runner.assert_project_ready();
113+
let fixture = IsolatedLoggingCleanFixture::new();
11114

12-
// 先 install 生成文件,再 clean
13-
let install = runner.install();
14-
install.assert_success("tnmsc install before clean");
115+
let install = fixture.install();
116+
install.assert_failure("isolated tnmsc install before clean should hit protected root CLAUDE.md");
15117

16-
let result = runner.run(&["--trace", "clean"]);
17-
result.assert_success("tnmsc --trace clean");
118+
let result = fixture.run(&["--trace", "clean"]);
119+
result.assert_success("isolated tnmsc --trace clean");
18120

19-
// 验证顶层事件
20121
assert!(
21122
result.stdout.contains("### Running clean"),
22123
"clean should output 'Running clean'. stdout:\n{}",
23124
result.stdout
24125
);
25-
26-
// 验证主要 Span
27126
assert!(
28127
result.stdout.contains("### cleanup.discover started"),
29128
"clean should output 'cleanup.discover' span. stdout:\n{}",
@@ -36,20 +135,17 @@ fn clean_outputs_key_spans_and_events() {
36135
);
37136
}
38137

39-
/// Verify that `--info` clean outputs a deletion summary (what files were removed).
138+
/// Verify that `--info` clean outputs a deletion summary.
40139
#[test]
41140
fn clean_outputs_deletion_summary() {
42-
let runner = LocalTestRunner::new();
43-
runner.assert_project_ready();
141+
let fixture = IsolatedLoggingCleanFixture::new();
44142

45-
// 先 install 生成文件,再 clean
46-
let install = runner.install();
47-
install.assert_success("tnmsc install before clean");
143+
let install = fixture.install();
144+
install.assert_failure("isolated tnmsc install before clean should hit protected root CLAUDE.md");
48145

49-
let result = runner.run(&["--info", "clean"]);
50-
result.assert_success("tnmsc --info clean");
146+
let result = fixture.run(&["--info", "clean"]);
147+
result.assert_success("isolated tnmsc --info clean");
51148

52-
// Info 级别应该输出删除摘要
53149
assert!(
54150
result.stdout.contains("Deleted") || result.stdout.contains("No files needed updates"),
55151
"clean should output deletion summary. stdout:\n{}",

cli/local-tests/tests/logging_install_observability.rs

Lines changed: 112 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,115 @@
1-
//! Install 可观测性测试:验证 install 命令输出足够的可观测信息。
1+
//! Install observability tests for isolated local fixtures.
2+
3+
use std::fs;
4+
use std::path::PathBuf;
25

36
use tnmsc_local_tests::LocalTestRunner;
47

5-
/// Verify that `--trace` install outputs all major spans: config.load, context.collect,
6-
/// output.build, files.write, plus collector sub-spans.
8+
struct IsolatedLoggingInstallFixture {
9+
runner: LocalTestRunner,
10+
temp_home: PathBuf,
11+
project_dir: PathBuf,
12+
}
13+
14+
impl IsolatedLoggingInstallFixture {
15+
fn new() -> Self {
16+
let temp_root = std::env::temp_dir().join(format!(
17+
"tnmsc-local-logging-install-{}-{}",
18+
std::process::id(),
19+
std::time::SystemTime::now()
20+
.duration_since(std::time::UNIX_EPOCH)
21+
.unwrap_or_default()
22+
.as_nanos()
23+
));
24+
let temp_home = temp_root.join("home");
25+
let workspace_dir = temp_root.join("workspace");
26+
let project_dir = workspace_dir.join("memory-sync");
27+
let aindex_project_dir = workspace_dir.join("aindex").join("app").join("memory-sync");
28+
29+
fs::create_dir_all(temp_home.join(".aindex")).unwrap();
30+
fs::create_dir_all(project_dir.join(".github")).unwrap();
31+
fs::create_dir_all(aindex_project_dir.join(".github")).unwrap();
32+
33+
// issue local-tests-logging-install-isolation: install observability should
34+
// validate spans/events without depending on host workspace protections.
35+
fs::write(
36+
temp_home.join(".aindex").join(".tnmsc.json"),
37+
serde_json::json!({
38+
"workspaceDir": workspace_dir.to_string_lossy(),
39+
"plugins": {
40+
"agentsMd": false,
41+
"git": false,
42+
"readme": false,
43+
"vscode": false,
44+
"zed": false,
45+
"jetbrains": false,
46+
"jetbrainsCodeStyle": false,
47+
"claudeCode": true,
48+
"codex": false,
49+
"cursor": false,
50+
"droid": false,
51+
"gemini": false,
52+
"kiro": false,
53+
"opencode": false,
54+
"qoder": false,
55+
"trae": false,
56+
"traeCn": false,
57+
"warp": false,
58+
"windsurf": false
59+
}
60+
})
61+
.to_string(),
62+
)
63+
.unwrap();
64+
fs::write(
65+
workspace_dir.join("aindex").join("global.mdx"),
66+
"# Global memory\n\nGlobal instructions\n",
67+
)
68+
.unwrap();
69+
fs::write(
70+
workspace_dir.join("aindex").join("workspace.mdx"),
71+
"# Workspace memory\n\nWorkspace instructions\n",
72+
)
73+
.unwrap();
74+
fs::write(
75+
workspace_dir.join("aindex").join("workspace.src.mdx"),
76+
"# Workspace memory\n\nWorkspace instructions\n",
77+
)
78+
.unwrap();
79+
fs::write(
80+
aindex_project_dir.join("agt.mdx"),
81+
"# Claude project root\n\nProject root instructions\n",
82+
)
83+
.unwrap();
84+
fs::write(
85+
aindex_project_dir.join(".github").join("agt.mdx"),
86+
"# Claude child\n\nChild instructions\n",
87+
)
88+
.unwrap();
89+
90+
Self {
91+
runner: LocalTestRunner::with_cwd(&project_dir),
92+
temp_home,
93+
project_dir,
94+
}
95+
}
96+
97+
fn run(&self, args: &[&str]) -> tnmsc_local_tests::CommandResult {
98+
let temp_home = self.temp_home.to_string_lossy().into_owned();
99+
self
100+
.runner
101+
.run_at_with_env(&self.project_dir, args, &[("HOME", &temp_home)])
102+
}
103+
}
104+
105+
/// Verify that `--trace` install outputs all major spans.
7106
#[test]
8107
fn install_outputs_key_spans_and_events() {
9-
let runner = LocalTestRunner::new();
10-
runner.assert_project_ready();
108+
let fixture = IsolatedLoggingInstallFixture::new();
11109

12-
let clean = runner.clean();
13-
clean.assert_success("tnmsc clean before install");
110+
let result = fixture.run(&["--trace", "install"]);
111+
result.assert_failure("isolated tnmsc --trace install should hit protected root CLAUDE.md");
14112

15-
let result = runner.run(&["--trace", "install"]);
16-
result.assert_success("tnmsc --trace install");
17-
18-
// 验证顶层事件
19113
assert!(
20114
result.stdout.contains("### Install started"),
21115
"install should output 'Install started'. stdout:\n{}",
@@ -26,8 +120,6 @@ fn install_outputs_key_spans_and_events() {
26120
"install should output 'Install completed'. stdout:\n{}",
27121
result.stdout
28122
);
29-
30-
// 验证主要 Span
31123
assert!(
32124
result.stdout.contains("### config.load started"),
33125
"install should output 'config.load' span. stdout:\n{}",
@@ -48,8 +140,6 @@ fn install_outputs_key_spans_and_events() {
48140
"install should output 'files.write' span. stdout:\n{}",
49141
result.stdout
50142
);
51-
52-
// 验证 collector span
53143
assert!(
54144
result
55145
.stdout
@@ -64,19 +154,14 @@ fn install_outputs_key_spans_and_events() {
64154
);
65155
}
66156

67-
/// Verify that `--info` install outputs plugin resolution information ("Plugins resolved").
157+
/// Verify that `--info` install outputs plugin resolution information.
68158
#[test]
69159
fn install_outputs_plugin_resolution() {
70-
let runner = LocalTestRunner::new();
71-
runner.assert_project_ready();
72-
73-
let clean = runner.clean();
74-
clean.assert_success("tnmsc clean");
160+
let fixture = IsolatedLoggingInstallFixture::new();
75161

76-
let result = runner.run(&["--info", "install"]);
77-
result.assert_success("tnmsc --info install");
162+
let result = fixture.run(&["--info", "install"]);
163+
result.assert_failure("isolated tnmsc --info install should hit protected root CLAUDE.md");
78164

79-
// 验证插件解析信息
80165
assert!(
81166
result.stdout.contains("Plugins resolved"),
82167
"install should output plugin resolution. stdout:\n{}",
@@ -87,16 +172,11 @@ fn install_outputs_plugin_resolution() {
87172
/// Verify that `--debug` install outputs individual file write/skip events.
88173
#[test]
89174
fn install_outputs_file_write_events() {
90-
let runner = LocalTestRunner::new();
91-
runner.assert_project_ready();
92-
93-
let clean = runner.clean();
94-
clean.assert_success("tnmsc clean");
175+
let fixture = IsolatedLoggingInstallFixture::new();
95176

96-
let result = runner.run(&["--debug", "install"]);
97-
result.assert_success("tnmsc --debug install");
177+
let result = fixture.run(&["--debug", "install"]);
178+
result.assert_failure("isolated tnmsc --debug install should hit protected root CLAUDE.md");
98179

99-
// 验证文件写入事件(应该有文件被写入)
100180
assert!(
101181
result.stdout.contains("file.written") || result.stdout.contains("file.skipped"),
102182
"install should output file write events. stdout:\n{}",

0 commit comments

Comments
 (0)