Wave 7: Phase 2 features - sync --all, external refs, cross-alias discovery, CI/CD, reliability tests (bd-1ky, bd-1bp, bd-1rk, bd-1lj, bd-gvr, bd-1x5)
- Sync --all with async concurrency, per-host throttling, failure budgets, resumable execution - External ref bundling at fetch time with origin tracking - Cross-alias discovery (--all-aliases) for list and search commands - CI/CD pipeline (.gitlab-ci.yml), cargo-deny config, Dockerfile, install script - Reliability test suite: crash consistency (8 tests), lock contention (3 tests), property-based (4 tests) - Criterion performance benchmarks (5 benchmarks) - Bug fix: doctor --fix now repairs missing index.json when raw.json exists - Bug fix: shared $ref references no longer incorrectly flagged as circular (refs.rs) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
126
benches/perf.rs
Normal file
126
benches/perf.rs
Normal file
@@ -0,0 +1,126 @@
|
||||
//! Performance benchmarks for core operations.
|
||||
//!
|
||||
//! Run with: `cargo bench`
|
||||
//! First run establishes baseline. Subsequent runs report regressions.
|
||||
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use criterion::{Criterion, criterion_group, criterion_main};
|
||||
|
||||
fn fixture_path(name: &str) -> PathBuf {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
PathBuf::from(manifest_dir)
|
||||
.join("tests")
|
||||
.join("fixtures")
|
||||
.join(name)
|
||||
}
|
||||
|
||||
fn load_petstore_json() -> serde_json::Value {
|
||||
let path = fixture_path("petstore.json");
|
||||
let bytes = fs::read(&path).expect("failed to read petstore.json fixture");
|
||||
serde_json::from_slice(&bytes).expect("failed to parse petstore.json")
|
||||
}
|
||||
|
||||
fn bench_json_parse(c: &mut Criterion) {
|
||||
let path = fixture_path("petstore.json");
|
||||
let bytes = fs::read(&path).expect("failed to read petstore.json fixture");
|
||||
|
||||
c.bench_function("parse_petstore_json", |b| {
|
||||
b.iter(|| {
|
||||
let _: serde_json::Value = serde_json::from_slice(&bytes).expect("parse failed");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_build_index(c: &mut Criterion) {
|
||||
let raw_json = load_petstore_json();
|
||||
|
||||
c.bench_function("build_index_petstore", |b| {
|
||||
b.iter(|| {
|
||||
// Simulate endpoint extraction (mirrors build_index core logic)
|
||||
if let Some(paths) = raw_json.get("paths").and_then(|v| v.as_object()) {
|
||||
let mut endpoints = Vec::new();
|
||||
for (path, methods) in paths {
|
||||
if let Some(methods_map) = methods.as_object() {
|
||||
for (method, _op) in methods_map {
|
||||
endpoints.push((path.clone(), method.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(!endpoints.is_empty());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_hash_computation(c: &mut Criterion) {
|
||||
let path = fixture_path("petstore.json");
|
||||
let bytes = fs::read(&path).expect("failed to read petstore.json");
|
||||
|
||||
c.bench_function("sha256_petstore", |b| {
|
||||
b.iter(|| {
|
||||
use sha2::{Digest, Sha256};
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(&bytes);
|
||||
let _result = format!("sha256:{:x}", hasher.finalize());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_json_pointer_resolution(c: &mut Criterion) {
|
||||
let raw_json = load_petstore_json();
|
||||
|
||||
c.bench_function("json_pointer_resolution", |b| {
|
||||
b.iter(|| {
|
||||
let _ = raw_json
|
||||
.pointer("/paths/~1pets/get/summary")
|
||||
.map(|v| v.as_str());
|
||||
let _ = raw_json
|
||||
.pointer("/components/schemas/Pet")
|
||||
.map(|v| v.is_object());
|
||||
let _ = raw_json.pointer("/info/title").map(|v| v.as_str());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_search_scoring(c: &mut Criterion) {
|
||||
let raw_json = load_petstore_json();
|
||||
|
||||
// Pre-extract summaries for search simulation
|
||||
let mut summaries: Vec<String> = Vec::new();
|
||||
if let Some(paths) = raw_json.get("paths").and_then(|v| v.as_object()) {
|
||||
for (_path, methods) in paths {
|
||||
if let Some(methods_map) = methods.as_object() {
|
||||
for (_method, op) in methods_map {
|
||||
if let Some(summary) = op.get("summary").and_then(|v| v.as_str()) {
|
||||
summaries.push(summary.to_lowercase());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.bench_function("search_scoring_pet", |b| {
|
||||
let query = "pet";
|
||||
b.iter(|| {
|
||||
let mut matches = 0u32;
|
||||
for summary in &summaries {
|
||||
if summary.contains(query) {
|
||||
matches += 1;
|
||||
}
|
||||
}
|
||||
assert!(matches > 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
bench_json_parse,
|
||||
bench_build_index,
|
||||
bench_hash_computation,
|
||||
bench_json_pointer_resolution,
|
||||
bench_search_scoring,
|
||||
);
|
||||
criterion_main!(benches);
|
||||
Reference in New Issue
Block a user