agtrace_testing/
fixtures.rs1use anyhow::Result;
9use std::fs;
10use std::path::{Path, PathBuf};
11
12pub struct SampleFiles {
14 samples_dir: PathBuf,
15}
16
17impl Default for SampleFiles {
18 fn default() -> Self {
19 Self::new()
20 }
21}
22
23impl SampleFiles {
24 pub fn new() -> Self {
28 let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
29 let samples_dir = manifest_dir
30 .parent()
31 .unwrap()
32 .join("agtrace-providers/tests/samples");
33
34 Self { samples_dir }
35 }
36
37 pub fn copy_to(&self, sample_name: &str, dest: &Path) -> Result<()> {
39 let source = self.samples_dir.join(sample_name);
40 fs::copy(source, dest)?;
41 Ok(())
42 }
43
44 pub fn copy_to_project(
48 &self,
49 sample_name: &str,
50 dest_name: &str,
51 project_dir: &str,
52 log_root: &Path,
53 ) -> Result<()> {
54 let source = self.samples_dir.join(sample_name);
55
56 let encoded = project_dir
58 .replace(['/', '.'], "-")
59 .trim_start_matches('-')
60 .to_string();
61 let encoded_dir = format!("-{}", encoded);
62
63 let project_log_dir = log_root.join(encoded_dir);
64 fs::create_dir_all(&project_log_dir)?;
65
66 let dest = project_log_dir.join(dest_name);
67 fs::copy(source, dest)?;
68 Ok(())
69 }
70
71 pub fn copy_to_project_with_cwd(
78 &self,
79 sample_name: &str,
80 dest_name: &str,
81 target_project_dir: &str,
82 log_root: &Path,
83 provider_adapter: &agtrace_providers::ProviderAdapter,
84 ) -> Result<()> {
85 let source = self.samples_dir.join(sample_name);
86
87 let canonical_project_dir = Path::new(target_project_dir)
89 .canonicalize()
90 .unwrap_or_else(|_| Path::new(target_project_dir).to_path_buf());
91 let canonical_str = canonical_project_dir.to_string_lossy();
92
93 let project_log_dir = if let Some(provider_subdir) = provider_adapter
107 .discovery
108 .resolve_log_root(&canonical_project_dir)
109 {
110 log_root.join(provider_subdir)
112 } else {
113 let encoded = target_project_dir
115 .replace(['/', '.'], "-")
116 .trim_start_matches('-')
117 .to_string();
118 let encoded_dir = format!("-{}", encoded);
119 log_root.join(encoded_dir)
120 };
121
122 fs::create_dir_all(&project_log_dir)?;
123
124 let dest = project_log_dir.join(dest_name);
125
126 let content = fs::read_to_string(&source)?;
128
129 let mut modified_content = content.replace(
131 r#""cwd":"/Users/test_user/agent-sample""#,
132 &format!(r#""cwd":"{}""#, canonical_str),
133 );
134
135 let project_hash = agtrace_types::project_hash_from_root(&canonical_str);
138 modified_content = modified_content.replace(
139 r#""projectHash": "9126eddec7f67e038794657b4d517dd9cb5226468f30b5ee7296c27d65e84fde""#,
140 &format!(r#""projectHash": "{}""#, project_hash),
141 );
142
143 let new_session_id = generate_session_id(target_project_dir, dest_name);
145
146 modified_content =
148 modified_content.replace("7f2abd2d-7cfc-4447-9ddd-3ca8d14e02e9", &new_session_id);
149
150 modified_content =
152 modified_content.replace("f0a689a6-b0ac-407f-afcc-4fafa9e14e8a", &new_session_id);
153
154 fs::write(dest, modified_content)?;
155 Ok(())
156 }
157}
158
159fn generate_session_id(project_dir: &str, filename: &str) -> String {
161 use sha2::{Digest, Sha256};
162
163 let mut hasher = Sha256::new();
164 hasher.update(project_dir.as_bytes());
165 hasher.update(filename.as_bytes());
166 let hash = hasher.finalize();
167
168 format!(
169 "test-session-{:016x}",
170 u64::from_be_bytes([
171 hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7]
172 ])
173 )
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 #[test]
181 fn test_generate_session_id_deterministic() {
182 let id1 = generate_session_id("/Users/test/project-a", "session1.jsonl");
183 let id2 = generate_session_id("/Users/test/project-a", "session1.jsonl");
184 assert_eq!(id1, id2);
185 }
186
187 #[test]
188 fn test_generate_session_id_unique() {
189 let id1 = generate_session_id("/Users/test/project-a", "session1.jsonl");
190 let id2 = generate_session_id("/Users/test/project-b", "session1.jsonl");
191 assert_ne!(id1, id2);
192 }
193}