Skip to content

Commit db3a8ab

Browse files
committed
feat: add caddy integration test; fix bug where benchmark was ovewritten
1 parent e28b88b commit db3a8ab

File tree

7 files changed

+158
-37
lines changed

7 files changed

+158
-37
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "go-runner/testdata/projects/caddy"]
2+
path = go-runner/testdata/projects/caddy
3+
url = https://github.com/caddyserver/caddy.git

go-runner/Cargo.lock

Lines changed: 49 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go-runner/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ thiserror = "2.0.12"
2222
[dev-dependencies]
2323
insta = { version = "1.43.1", features = ["json"] }
2424
rstest = "0.25.0"
25+
tempfile = "3.14.0"

go-runner/src/builder/templater.rs

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,13 @@
1+
use std::fs;
12
use std::path::{Path, PathBuf};
2-
use std::{fs, io};
33

44
use handlebars::Handlebars;
55
use serde::{Deserialize, Serialize};
66

77
use crate::builder::{BenchmarkData, GoPackage};
8+
use crate::utils;
89
use crate::{builder::patcher, prelude::*};
910

10-
fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
11-
fs::create_dir_all(&dst)?;
12-
for entry in fs::read_dir(src)? {
13-
let entry = entry?;
14-
let ty = entry.file_type()?;
15-
if ty.is_dir() {
16-
copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
17-
} else {
18-
fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
19-
}
20-
}
21-
Ok(())
22-
}
23-
2411
// FIXME: Move this to the discovery -> Create a new GoPackage which has a list of benchmarks
2512
fn find_benchmark_files(
2613
target_dir: &Path,
@@ -86,7 +73,7 @@ pub fn run(package: &GoPackage) -> anyhow::Result<(PathBuf, PathBuf)> {
8673
fs::remove_dir_all(&target_dir).context("Failed to remove existing target directory")?;
8774
}
8875
std::fs::create_dir_all(&target_dir).context("Failed to create target directory")?;
89-
copy_dir_all(&package.module.dir, &target_dir)?;
76+
utils::copy_dir_all(&package.module.dir, &target_dir)?;
9077

9178
// Get files that need to be renamed first
9279
let files = package
@@ -96,12 +83,10 @@ pub fn run(package: &GoPackage) -> anyhow::Result<(PathBuf, PathBuf)> {
9683
// Calculate the relative path from module root to package directory
9784
let package_dir = Path::new(&package.dir);
9885
let module_dir = Path::new(&package.module.dir);
99-
let relative_package_path = package_dir.strip_prefix(module_dir).context(
100-
format!(
101-
"Package dir {} is not within module dir {}",
102-
package.dir, package.module.dir
103-
)
104-
)?;
86+
let relative_package_path = package_dir.strip_prefix(module_dir).context(format!(
87+
"Package dir {} is not within module dir {}",
88+
package.dir, package.module.dir
89+
))?;
10590
info!("Relative package path: {}", relative_package_path.display());
10691

10792
// 2. Find benchmark files and patch only their imports
@@ -120,13 +105,11 @@ pub fn run(package: &GoPackage) -> anyhow::Result<(PathBuf, PathBuf)> {
120105
.replace("_test", "_codspeed"),
121106
);
122107

123-
fs::rename(&old_path, &new_path).context(
124-
format!(
125-
"Failed to rename {} to {}",
126-
old_path.display(),
127-
new_path.display()
128-
)
129-
)?;
108+
fs::rename(&old_path, &new_path).context(format!(
109+
"Failed to rename {} to {}",
110+
old_path.display(),
111+
new_path.display()
112+
))?;
130113
}
131114

132115
// 4. Generate the codspeed/runner.go file using the template

go-runner/src/integration_tests.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use crate::prelude::*;
2+
use std::path::{Path, PathBuf};
3+
use tempfile::TempDir;
4+
5+
fn setup_test_project(project_name: &str) -> (TempDir, PathBuf) {
6+
let project_path = Path::new("testdata/projects").join(project_name);
7+
let temp_dir = TempDir::new().unwrap();
8+
let test_dir = temp_dir.path();
9+
10+
crate::utils::copy_dir_all(&project_path, test_dir.join(project_name)).unwrap();
11+
let project_test_path = test_dir.join(project_name);
12+
13+
std::env::set_current_dir(&project_test_path).unwrap();
14+
15+
(temp_dir, project_test_path)
16+
}
17+
18+
/// Integration tests with real Go projects to ensure end-to-end functionality
19+
#[cfg(test)]
20+
mod tests {
21+
use super::*;
22+
23+
fn assert_benchmarks_created(n: usize) {
24+
let codspeed_dir = std::env::current_dir()
25+
.unwrap()
26+
.join(".codspeed")
27+
.join("walltime");
28+
assert!(codspeed_dir.exists());
29+
30+
let entries: Vec<_> = std::fs::read_dir(&codspeed_dir)
31+
.unwrap()
32+
.collect::<Result<Vec<_>, _>>()
33+
.unwrap();
34+
assert_eq!(entries.len(), n);
35+
}
36+
37+
#[test]
38+
fn test_caddy_benchmarks() {
39+
let (_temp_dir, caddy_test_path) = setup_test_project("caddy");
40+
41+
let binaries = crate::build_benchmarks(&caddy_test_path).unwrap();
42+
assert!(!binaries.is_empty(), "No benchmark binaries were created");
43+
assert_benchmarks_created(binaries.len());
44+
45+
// FIXME: Find a better solution for this
46+
unsafe {
47+
std::env::set_var("CODSPEED_PROFILE_FOLDER", caddy_test_path.join("profile"));
48+
}
49+
crate::run_benchmarks(".").unwrap();
50+
}
51+
}

go-runner/src/lib.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ use std::{
77
mod builder;
88
pub mod prelude;
99
mod results;
10+
pub(crate) mod utils;
11+
12+
#[cfg(test)]
13+
mod integration_tests;
1014

1115
/// Builds the specified go project and writes the benchmarks to the .codspeed folder.
1216
pub fn build_benchmarks(project_dir: &Path) -> anyhow::Result<Vec<PathBuf>> {
@@ -33,19 +37,29 @@ pub fn build_benchmarks(project_dir: &Path) -> anyhow::Result<Vec<PathBuf>> {
3337
binaries.push(builder::runner::build(&runner_path)?);
3438
}
3539

36-
// 3. Copy them to the .codspeed folder
40+
// 4. Copy them to the .codspeed folder
3741
let codspeed_dir = std::env::current_dir()?.join(".codspeed").join("walltime");
3842

3943
debug!("Creating codspeed directory: {}", codspeed_dir.display());
4044
std::fs::create_dir_all(&codspeed_dir)?;
4145

42-
for binary in &binaries {
43-
let target_path = codspeed_dir.join(binary.file_name().unwrap());
44-
debug!("Copying {} to {}", binary.display(), target_path.display());
45-
std::fs::copy(binary, &target_path)?;
46+
let mut copied_binaries = Vec::new();
47+
for binary_path in &binaries {
48+
// Create a unique filename to avoid accidentally overwriting existing benchmarks.
49+
let filename = binary_path.file_name().unwrap().to_string_lossy();
50+
let unique_filename = format!("{}_{:08x}", filename, rand::random::<u32>());
51+
let target_path = codspeed_dir.join(unique_filename);
52+
53+
debug!(
54+
"Copying {} to {}",
55+
binary_path.display(),
56+
target_path.display()
57+
);
58+
std::fs::copy(binary_path, &target_path)?;
59+
copied_binaries.push(target_path);
4660
}
4761

48-
Ok(binaries)
62+
Ok(copied_binaries)
4963
}
5064

5165
pub fn run_benchmarks(bench: &str) -> anyhow::Result<()> {
@@ -70,8 +84,8 @@ pub fn run_benchmarks(bench: &str) -> anyhow::Result<()> {
7084
let stdout = String::from_utf8_lossy(&cmd.stdout);
7185
let stderr = String::from_utf8_lossy(&cmd.stderr);
7286

73-
info!("Command output: {stdout}");
74-
info!("Command error output: {stderr}");
87+
warn!("Command output: {stdout}");
88+
warn!("Command error output: {stderr}");
7589

7690
bail!(
7791
"Failed to run benchmark: {}. Exit status: {}",

go-runner/src/utils.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use std::path::Path;
2+
use std::{fs, io};
3+
4+
pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
5+
fs::create_dir_all(&dst)?;
6+
for entry in fs::read_dir(src)? {
7+
let entry = entry?;
8+
let ty = entry.file_type()?;
9+
if ty.is_dir() {
10+
if entry.file_name() == ".git" {
11+
continue;
12+
}
13+
14+
copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
15+
} else {
16+
fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
17+
}
18+
}
19+
Ok(())
20+
}

0 commit comments

Comments
 (0)