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
95 .discovery
96 .resolve_log_root(&canonical_project_dir)
97 {
98 log_root.join(provider_subdir)
100 } else {
101 let encoded = target_project_dir
103 .replace(['/', '.'], "-")
104 .trim_start_matches('-')
105 .to_string();
106 let encoded_dir = format!("-{}", encoded);
107 log_root.join(encoded_dir)
108 };
109
110 fs::create_dir_all(&project_log_dir)?;
111
112 let dest = project_log_dir.join(dest_name);
113
114 let content = fs::read_to_string(&source)?;
116
117 let mut modified_content = content.replace(
119 r#""cwd":"/Users/test_user/agent-sample""#,
120 &format!(r#""cwd":"{}""#, canonical_str),
121 );
122
123 let project_hash = agtrace_types::project_hash_from_root(&canonical_str);
126 modified_content = modified_content.replace(
127 r#""projectHash": "9126eddec7f67e038794657b4d517dd9cb5226468f30b5ee7296c27d65e84fde""#,
128 &format!(r#""projectHash": "{}""#, project_hash),
129 );
130
131 let new_session_id = generate_session_id(target_project_dir, dest_name);
133
134 modified_content =
136 modified_content.replace("7f2abd2d-7cfc-4447-9ddd-3ca8d14e02e9", &new_session_id);
137
138 modified_content =
140 modified_content.replace("f0a689a6-b0ac-407f-afcc-4fafa9e14e8a", &new_session_id);
141
142 fs::write(dest, modified_content)?;
143 Ok(())
144 }
145}
146
147fn generate_session_id(project_dir: &str, filename: &str) -> String {
149 use sha2::{Digest, Sha256};
150
151 let mut hasher = Sha256::new();
152 hasher.update(project_dir.as_bytes());
153 hasher.update(filename.as_bytes());
154 let hash = hasher.finalize();
155
156 format!(
157 "test-session-{:016x}",
158 u64::from_be_bytes([
159 hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7]
160 ])
161 )
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn test_generate_session_id_deterministic() {
170 let id1 = generate_session_id("/Users/test/project-a", "session1.jsonl");
171 let id2 = generate_session_id("/Users/test/project-a", "session1.jsonl");
172 assert_eq!(id1, id2);
173 }
174
175 #[test]
176 fn test_generate_session_id_unique() {
177 let id1 = generate_session_id("/Users/test/project-a", "session1.jsonl");
178 let id2 = generate_session_id("/Users/test/project-b", "session1.jsonl");
179 assert_ne!(id1, id2);
180 }
181}