utils.rs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /// A simple RAII guard that resets an env var after the test exits
  2. pub struct EnvVarGuard {
  3. key: String,
  4. original: Option<String>,
  5. }
  6. impl EnvVarGuard {
  7. pub fn new<K: Into<String>, V: Into<String>>(key: K, value: V) -> Self {
  8. let key = key.into();
  9. let original = std::env::var(&key).ok();
  10. unsafe {
  11. std::env::set_var(&key, value.into());
  12. }
  13. Self { key, original }
  14. }
  15. }
  16. impl Drop for EnvVarGuard {
  17. fn drop(&mut self) {
  18. if let Some(ref val) = self.original {
  19. unsafe {
  20. std::env::set_var(&self.key, val);
  21. }
  22. } else {
  23. unsafe {
  24. std::env::remove_var(&self.key);
  25. }
  26. }
  27. }
  28. }
  29. use std::{
  30. fs,
  31. path::PathBuf,
  32. process::{Command, Output},
  33. };
  34. /// Test environment setup for SBPF tests
  35. pub struct TestEnv {
  36. pub sbpf_bin: String,
  37. pub temp_dir: PathBuf,
  38. pub project_dir: PathBuf,
  39. pub _guard: EnvVarGuard,
  40. }
  41. impl TestEnv {
  42. /// Set up a test environment with SBPF binary and temporary directory
  43. pub fn new(project_name: &str) -> Self {
  44. let current_dir = std::env::current_dir().expect("Failed to get current directory");
  45. let sbpf_path = current_dir.join("target").join("debug").join("sbpf");
  46. let guard = EnvVarGuard::new("SBPF_BIN", sbpf_path.to_string_lossy());
  47. let sbpf_bin = std::env::var("SBPF_BIN").expect("SBPF_BIN not set");
  48. let temp_dir = std::env::temp_dir().join(format!("sbpf_test_{}_e2e", project_name));
  49. if temp_dir.exists() {
  50. fs::remove_dir_all(&temp_dir).expect("Failed to remove existing test directory");
  51. }
  52. fs::create_dir_all(&temp_dir).expect("Failed to create test directory");
  53. let project_dir = temp_dir.join(project_name);
  54. println!("Using test directory: {:?}", temp_dir);
  55. println!("Using project directory: {:?}", project_dir);
  56. Self {
  57. sbpf_bin,
  58. temp_dir,
  59. project_dir,
  60. _guard: guard,
  61. }
  62. }
  63. /// Clean up the test environment
  64. pub fn cleanup(self) {
  65. fs::remove_dir_all(&self.temp_dir).expect("Failed to remove test directory");
  66. }
  67. }
  68. /// Run a command and return the output, panicking on failure
  69. pub fn run_command(cmd: &mut Command, operation_name: &str) -> Output {
  70. let output = cmd
  71. .output()
  72. .unwrap_or_else(|_| panic!("Failed to execute {}", operation_name));
  73. if !output.status.success() {
  74. let stderr = String::from_utf8_lossy(&output.stderr);
  75. let stdout = String::from_utf8_lossy(&output.stdout);
  76. panic!(
  77. "{} failed:\nSTDOUT: {}\nSTDERR: {}",
  78. operation_name, stdout, stderr
  79. );
  80. }
  81. println!("✅ {} completed successfully", operation_name);
  82. println!("STDOUT: {}", String::from_utf8_lossy(&output.stdout));
  83. output
  84. }
  85. /// Initialize a new SBPF project
  86. pub fn init_project(env: &TestEnv, project_name: &str) {
  87. println!("Step 1: Initializing {} project...", project_name);
  88. let init_output = run_command(
  89. Command::new(&env.sbpf_bin)
  90. .current_dir(&env.temp_dir)
  91. .arg("init")
  92. .arg(project_name),
  93. &format!("target/debug/sbpf init {}", project_name),
  94. );
  95. println!("✅ Project initialized successfully");
  96. println!("STDOUT: {}", String::from_utf8_lossy(&init_output.stdout));
  97. }
  98. /// Verify that the project structure is correct
  99. pub fn verify_project_structure(env: &TestEnv, project_name: &str) {
  100. let project_dir = &env.project_dir;
  101. assert!(
  102. project_dir.join("src").exists(),
  103. "src directory should exist"
  104. );
  105. assert!(
  106. project_dir.join("deploy").exists(),
  107. "deploy directory should exist"
  108. );
  109. assert!(
  110. project_dir.join(format!("src/{}", project_name)).exists(),
  111. "src/{} directory should exist",
  112. project_name
  113. );
  114. assert!(
  115. project_dir
  116. .join(format!("src/{}/{}.s", project_name, project_name))
  117. .exists(),
  118. "src/{}/{}.s should exist",
  119. project_name,
  120. project_name
  121. );
  122. assert!(
  123. project_dir.join("src/lib.rs").exists(),
  124. "src/lib.rs should exist"
  125. );
  126. assert!(
  127. project_dir.join("Cargo.toml").exists(),
  128. "Cargo.toml should exist"
  129. );
  130. }
  131. /// Run build on the project
  132. pub fn run_build(env: &TestEnv) {
  133. println!("Step 3: Running build...");
  134. run_command(
  135. Command::new(&env.sbpf_bin)
  136. .current_dir(&env.project_dir)
  137. .arg("build"),
  138. "target/debug/sbpf build",
  139. );
  140. }
  141. /// Verify that .so files were created in the deploy directory
  142. pub fn verify_so_files(env: &TestEnv) {
  143. let deploy_dir = env.project_dir.join("deploy");
  144. assert!(deploy_dir.exists(), "deploy directory should exist");
  145. let so_files: Vec<_> = fs::read_dir(&deploy_dir)
  146. .expect("Failed to read deploy directory")
  147. .filter_map(|entry| entry.ok())
  148. .filter(|entry| {
  149. entry
  150. .path()
  151. .extension()
  152. .and_then(|ext| ext.to_str())
  153. .map(|ext| ext == "so")
  154. .unwrap_or(false)
  155. })
  156. .collect();
  157. assert!(
  158. !so_files.is_empty(),
  159. "At least one .so file should be created in deploy directory"
  160. );
  161. println!("Found {} .so file(s) in deploy directory", so_files.len());
  162. }
  163. /// Run tests on the project
  164. #[allow(dead_code)]
  165. pub fn run_tests(env: &TestEnv) {
  166. println!("Step 4: Running tests...");
  167. run_command(
  168. Command::new(&env.sbpf_bin)
  169. .current_dir(&env.project_dir)
  170. .arg("test"),
  171. "target/debug/sbpf test",
  172. );
  173. }
  174. /// Update the project's assembly file content
  175. pub fn update_assembly_file(env: &TestEnv, project_name: &str, content: &str) {
  176. let assembly_path = env
  177. .project_dir
  178. .join(format!("src/{}/{}.s", project_name, project_name));
  179. fs::write(&assembly_path, content)
  180. .unwrap_or_else(|_| panic!("Failed to write new {}.s content", project_name));
  181. println!("✅ Updated {}.s with specified content", project_name);
  182. }