#![allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::needless_raw_string_hashes,
clippy::duration_suboptimal_units,
clippy::branches_sharing_code,
clippy::used_underscore_binding,
clippy::single_char_pattern,
clippy::ignore_without_reason,
clippy::cloned_ref_to_slice_refs,
clippy::doc_overindented_list_items,
clippy::match_wildcard_for_single_variants,
clippy::ignored_unit_patterns,
clippy::needless_collect,
clippy::unnecessary_map_or,
clippy::manual_flatten,
clippy::manual_strip,
clippy::future_not_send,
clippy::unnested_or_patterns,
clippy::no_effect_underscore_binding,
clippy::literal_string_with_formatting_args
)]
use assert_cmd::Command;
use assert_fs::prelude::*;
use assert_fs::TempDir;
use std::sync::Arc;
use std::thread;
use std::time::{Duration, Instant};
#[test]
fn perf_startup_time_help_command() {
let start = Instant::now();
Command::new(env!("CARGO_BIN_EXE_ggen"))
.args(["--help"])
.assert()
.success();
let elapsed = start.elapsed();
assert!(
elapsed < Duration::from_secs(10),
"CLI startup took {:?}, should be <10s",
elapsed
);
}
#[test]
fn perf_startup_time_version_command() {
let start = Instant::now();
Command::new(env!("CARGO_BIN_EXE_ggen"))
.args(["--version"])
.assert()
.success();
let elapsed = start.elapsed();
assert!(
elapsed < Duration::from_secs(10),
"Version command took {:?}, should be <10s",
elapsed
);
}
#[test]
fn perf_startup_time_subcommand_help() {
for subcommand in &["sync", "init", "pack", "receipt"] {
let start = Instant::now();
Command::new(env!("CARGO_BIN_EXE_ggen"))
.args([*subcommand, "--help"])
.assert()
.success();
let elapsed = start.elapsed();
assert!(
elapsed < Duration::from_secs(10),
"{} help took {:?}, should be <10s",
subcommand,
elapsed
);
}
}
#[test]
fn perf_cold_start_with_config() {
let temp = TempDir::new().unwrap();
let manifest_file = temp.child("ggen.toml");
manifest_file
.write_str(
r#"
[project]
name = "test"
version = "0.1.0"
description = "Performance test project"
[ontology]
source = "schema/domain.ttl"
[[inference.rules]]
name = "inf_rule"
construct = "CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o }"
[[generation.rules]]
name = "api"
query = { file = "queries/api.rq" }
template = { file = "templates/api.rs.tera" }
output_file = "src/api.rs"
"#,
)
.unwrap();
let schema_dir = temp.child("schema");
std::fs::create_dir_all(schema_dir.path()).unwrap();
schema_dir.child("domain.ttl").write_str("").unwrap();
let queries_dir = temp.child("queries");
std::fs::create_dir_all(queries_dir.path()).unwrap();
queries_dir
.child("api.rq")
.write_str("SELECT ?s WHERE { ?s ?p ?o }")
.unwrap();
let templates_dir = temp.child("templates");
std::fs::create_dir_all(templates_dir.path()).unwrap();
templates_dir
.child("api.rs.tera")
.write_str("hello")
.unwrap();
let start = Instant::now();
Command::new(env!("CARGO_BIN_EXE_ggen"))
.args([
"sync",
"--manifest",
manifest_file.path().to_str().unwrap(),
"--dry_run",
"true",
])
.current_dir(temp.path())
.assert()
.success();
let elapsed = start.elapsed();
assert!(
elapsed < Duration::from_secs(10),
"Cold start with config took {:?}, should be <10s",
elapsed
);
}
#[test]
#[cfg(target_os = "linux")]
fn perf_memory_usage_basic_command() {
use std::process::{Command as StdCommand, Stdio};
let mut child = StdCommand::new(env!("CARGO_BIN_EXE_ggen"))
.args(["--help"])
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.unwrap();
thread::sleep(Duration::from_millis(100));
let status_path = format!("/proc/{}/status", child.id());
if let Ok(status) = std::fs::read_to_string(&status_path) {
for line in status.lines() {
if line.starts_with("VmRSS:") {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() >= 2 {
let memory_kb: u64 = parts[1].parse().unwrap_or(0);
let memory_mb = memory_kb / 1024;
assert!(
memory_mb < 120,
"Memory usage is {}MB, should be <120MB",
memory_mb
);
}
break;
}
}
}
let _ = child.wait();
}
#[test]
#[ignore = "ggen template subcommand removed; CLI consolidated to ggen sync (v26_5_19+)"]
fn perf_memory_stress_large_template() {
let temp = TempDir::new().unwrap();
let template_file = temp.child("large.yaml");
let output_dir = temp.child("output");
let mut template = String::from(
r#"
name: "memory-test"
variables:
- name: project_name
required: true
nodes:
- name: "{{project_name}}"
type: directory
children:
"#,
);
for i in 0..100 {
template.push_str(&format!(
r#"
- name: "module_{}/lib.rs"
type: file
content: |
// Module {}
pub fn function_{}() {{
println!("Function {0}");
}}
"#,
i, i, i
));
}
template_file.write_str(&template).unwrap();
Command::cargo_bin("ggen")
.unwrap()
.args([
"template",
"generate_tree",
"--template",
template_file.path().to_str().unwrap(),
"--output",
output_dir.path().to_str().unwrap(),
"--var",
"project_name=large-project",
])
.timeout(Duration::from_secs(30))
.assert()
.success();
}
#[test]
fn perf_concurrent_help_commands() {
let handles: Vec<_> = (0..5)
.map(|_| {
thread::spawn(|| {
Command::new(env!("CARGO_BIN_EXE_ggen"))
.args(["--help"])
.assert()
.success();
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
}
#[test]
fn perf_concurrent_version_commands() {
let handles: Vec<_> = (0..10)
.map(|_| {
thread::spawn(|| {
Command::new(env!("CARGO_BIN_EXE_ggen"))
.args(["--version"])
.assert()
.success();
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
}
#[test]
#[ignore = "ggen template subcommand removed; CLI consolidated to ggen sync (v26_5_19+)"]
fn perf_concurrent_template_generation() {
let temp = Arc::new(TempDir::new().unwrap());
let template_file = temp.child("template.yaml");
template_file
.write_str(
r#"
name: "concurrent-test"
variables:
- name: id
required: true
nodes:
- name: "output_{{id}}"
type: directory
children:
- name: "file.txt"
type: file
content: "ID: {{id}}"
"#,
)
.unwrap();
let handles: Vec<_> = (0..3)
.map(|i| {
let temp_clone = Arc::clone(&temp);
let template_path = template_file.path().to_path_buf();
thread::spawn(move || {
let output_dir = temp_clone.child(format!("output_{}", i));
Command::cargo_bin("ggen")
.unwrap()
.args([
"template",
"generate_tree",
"--template",
template_path.to_str().unwrap(),
"--output",
output_dir.path().to_str().unwrap(),
"--var",
&format!("id={}", i),
])
.assert()
.success();
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
}
#[test]
fn perf_concurrent_marketplace_searches() {
let queries = vec!["rust", "cli", "web", "api", "template"];
let handles: Vec<_> = queries
.into_iter()
.map(|query| {
thread::spawn(move || {
Command::new(env!("CARGO_BIN_EXE_ggen"))
.args(["pack", "search", query, "--limit", "5"])
.assert()
.success();
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
}
#[test]
fn perf_response_time_doctor_command() {
let start = Instant::now();
Command::new(env!("CARGO_BIN_EXE_ggen"))
.args(["doctor"])
.assert()
.success();
let elapsed = start.elapsed();
assert!(
elapsed < Duration::from_secs(5),
"Doctor command took {:?}, should be <5s",
elapsed
);
}
#[test]
fn perf_response_time_marketplace_search() {
let start = Instant::now();
Command::new(env!("CARGO_BIN_EXE_ggen"))
.args(["pack", "search", "rust", "--limit", "10"])
.assert()
.success();
let elapsed = start.elapsed();
assert!(
elapsed < Duration::from_secs(10),
"Marketplace search took {:?}, should be <10s",
elapsed
);
}
#[test]
#[ignore = "ggen template subcommand removed; CLI consolidated to ggen sync (v26_5_19+)"]
fn perf_response_time_simple_template() {
let temp = TempDir::new().unwrap();
let template_file = temp.child("simple.yaml");
let output_dir = temp.child("output");
template_file
.write_str(
r##"
name: "simple"
variables:
- name: name
required: true
nodes:
- name: "{{name}}"
type: directory
children:
- name: "README.md"
type: file
content: "# {{name}}"
"##,
)
.unwrap();
let start = Instant::now();
Command::cargo_bin("ggen")
.unwrap()
.args([
"template",
"generate_tree",
"--template",
template_file.path().to_str().unwrap(),
"--output",
output_dir.path().to_str().unwrap(),
"--var",
"name=test",
])
.assert()
.success();
let elapsed = start.elapsed();
assert!(
elapsed < Duration::from_secs(5),
"Simple template generation took {:?}, should be <5s",
elapsed
);
}
#[test]
#[ignore = "ggen template subcommand removed; CLI consolidated to ggen sync (v26_5_19+)"]
fn perf_scalability_many_variables() {
let temp = TempDir::new().unwrap();
let template_file = temp.child("many-vars.yaml");
let output_dir = temp.child("output");
let mut template = String::from(
r#"
name: "many-vars"
variables:
"#,
);
for i in 0..50 {
template.push_str(&format!(
r#"
- name: var_{}
default: "value_{}"
"#,
i, i
));
}
template.push_str(
r#"
nodes:
- name: "output"
type: directory
children:
- name: "config.txt"
type: file
content: "Configuration file"
"#,
);
template_file.write_str(&template).unwrap();
let start = Instant::now();
Command::cargo_bin("ggen")
.unwrap()
.args([
"template",
"generate_tree",
"--template",
template_file.path().to_str().unwrap(),
"--output",
output_dir.path().to_str().unwrap(),
])
.assert()
.success();
let elapsed = start.elapsed();
assert!(
elapsed < Duration::from_secs(10),
"Many variables template took {:?}, should be <10s",
elapsed
);
}
#[test]
#[ignore = "ggen template subcommand removed; CLI consolidated to ggen sync (v26_5_19+)"]
fn perf_scalability_deep_nesting() {
let temp = TempDir::new().unwrap();
let template_file = temp.child("deep.yaml");
let output_dir = temp.child("output");
let mut template = String::from(
r#"
name: "deep-structure"
variables:
- name: project_name
required: true
nodes:
- name: "{{project_name}}"
type: directory
children:
"#,
);
let mut indent = " ";
for i in 0..10 {
template.push_str(&format!(
r#"
{} - name: "level_{}"
{} type: directory
{} children:
"#,
indent, i, indent, indent
));
indent = &indent[0..indent.len().saturating_sub(2)];
}
template.push_str(
r#"
- name: "deepest.txt"
type: file
content: "Deepest level"
"#,
);
template_file.write_str(&template).unwrap();
Command::cargo_bin("ggen")
.unwrap()
.args([
"template",
"generate_tree",
"--template",
template_file.path().to_str().unwrap(),
"--output",
output_dir.path().to_str().unwrap(),
"--var",
"project_name=deep-test",
])
.timeout(Duration::from_secs(15))
.assert()
.success();
}
#[test]
fn perf_no_resource_leaks_repeated_commands() {
for _ in 0..10 {
Command::new(env!("CARGO_BIN_EXE_ggen"))
.args(["--version"])
.assert()
.success();
}
}
#[test]
fn perf_no_resource_leaks_failed_commands() {
for _ in 0..5 {
let _ = Command::new(env!("CARGO_BIN_EXE_ggen"))
.args(["sync", "--invalid-flag-that-does-not-exist"])
.assert()
.failure();
}
}
#[test]
#[ignore = "ggen template subcommand removed; CLI consolidated to ggen sync (v26_5_19+)"]
fn perf_throughput_sequential_generations() {
let temp = TempDir::new().unwrap();
let template_file = temp.child("template.yaml");
template_file
.write_str(
r##"
name: "throughput-test"
variables:
- name: id
required: true
nodes:
- name: "project_{{id}}"
type: directory
children:
- name: "README.md"
type: file
content: "# Project {{id}}"
"##,
)
.unwrap();
let start = Instant::now();
for i in 0..5 {
let output_dir = temp.child(format!("output_{}", i));
Command::cargo_bin("ggen")
.unwrap()
.args([
"template",
"generate_tree",
"--template",
template_file.path().to_str().unwrap(),
"--output",
output_dir.path().to_str().unwrap(),
"--var",
&format!("id={}", i),
])
.assert()
.success();
}
let elapsed = start.elapsed();
let avg_per_generation = elapsed / 5;
assert!(
avg_per_generation < Duration::from_secs(3),
"Average generation time {:?}, should be <3s",
avg_per_generation
);
}