use anyhow::Result;
use std::time::Instant;
use crate::common::{ManifestBuilder, TestProject};
#[tokio::test]
async fn test_parallel_transitive_resolution() -> Result<()> {
agpm_cli::test_utils::init_test_logging(None);
let project = TestProject::new().await?;
let community_repo = project.create_source_repo("community").await?;
for i in 0..10 {
community_repo
.add_resource(
"agents",
&format!("helper-{:02}", i),
format!(
r#"---
# Helper Agent {:02}
This is helper agent {} with no dependencies.
---
"#,
i, i
)
.as_str(),
)
.await?;
}
for i in 0..15 {
let mut dependencies = String::from("dependencies:\n agents:\n");
let dep_count = 2 + (i % 2);
for j in 0..dep_count {
let helper_idx = (i * 2 + j) % 10;
dependencies.push_str(&format!(
" - path: ./helper-{:02}.md\n version: v1.0.0\n",
helper_idx
));
}
community_repo
.add_resource(
"agents",
&format!("main-{:02}", i),
format!(
r#"---
{}
---
# Main Agent {:02}
This agent depends on {} helper agents.
"#,
dependencies, i, dep_count
)
.as_str(),
)
.await?;
}
community_repo.commit_all("Initial commit")?;
community_repo.tag_version("v1.0.0")?;
let source_url = community_repo.bare_file_url(project.sources_path()).await?;
let mut builder = ManifestBuilder::new().add_source("community", &source_url);
for i in 0..15 {
builder = builder.add_standard_agent(
&format!("main-{:02}", i),
"community",
&format!("agents/main-{:02}.md", i),
);
}
let manifest = builder.build();
project.write_manifest(&manifest).await?;
let start_time = Instant::now();
let output = project.run_agpm(&["install"])?;
assert!(output.success, "Install should succeed. Stderr: {}", output.stderr);
let install_duration = start_time.elapsed();
let lockfile_content = project.read_lockfile().await?;
for i in 0..15 {
assert!(
lockfile_content.contains(&format!("main-{:02}", i)),
"Main agent {:02} should be in lockfile",
i
);
}
let mut helper_count = 0;
for i in 0..10 {
if lockfile_content.contains(&format!("helper-{:02}", i)) {
helper_count += 1;
}
}
assert!(
helper_count > 0,
"At least some helper agents should be in lockfile as transitive dependencies"
);
let agents_dir = project.project_path().join(".claude/agents/agpm");
let mut agent_count = 0;
let mut entries = tokio::fs::read_dir(&agents_dir).await?;
while let Some(_entry) = entries.next_entry().await? {
agent_count += 1;
}
assert!(agent_count >= 15, "At least 15 agents should be installed (got {})", agent_count);
println!(
"Parallel install of {} agents completed in {:?} ({:.2} agents/sec)",
agent_count,
install_duration,
agent_count as f64 / install_duration.as_secs_f64()
);
Ok(())
}
#[tokio::test]
async fn test_concurrent_dependency_access() -> Result<()> {
agpm_cli::test_utils::init_test_logging(None);
let project = TestProject::new().await?;
let community_repo = project.create_source_repo("community").await?;
community_repo
.add_resource(
"agents",
"shared-helper",
r#"---
# Shared Helper Agent
This helper is depended upon by many agents.
---
"#,
)
.await?;
for i in 0..20 {
community_repo
.add_resource(
"agents",
&format!("agent-{:02}", i),
format!(
r#"---
dependencies:
agents:
- path: ./shared-helper.md
version: v1.0.0
---
# Agent {:02}
This agent depends on the shared helper.
"#,
i
)
.as_str(),
)
.await?;
}
community_repo.commit_all("Initial commit")?;
community_repo.tag_version("v1.0.0")?;
let source_url = community_repo.bare_file_url(project.sources_path()).await?;
let mut builder = ManifestBuilder::new().add_source("community", &source_url);
for i in 0..20 {
builder = builder.add_standard_agent(
&format!("agent-{:02}", i),
"community",
&format!("agents/agent-{:02}.md", i),
);
}
let manifest = builder.build();
project.write_manifest(&manifest).await?;
let output = project.run_agpm(&["install"])?;
assert!(output.success, "Install should succeed. Stderr: {}", output.stderr);
let agents_dir = project.project_path().join(".claude/agents/agpm");
let shared_helper_path = agents_dir.join("shared-helper.md");
assert!(
tokio::fs::metadata(&shared_helper_path).await.is_ok(),
"Shared helper should be installed"
);
let mut agent_count = 0;
let mut entries = tokio::fs::read_dir(&agents_dir).await?;
while let Some(entry) = entries.next_entry().await? {
let file_name = entry.file_name();
let name = file_name.to_string_lossy();
if name.starts_with("agent-") {
agent_count += 1;
}
}
assert_eq!(agent_count, 20, "All 20 agents should be installed");
for i in 0..20 {
let agent_path = agents_dir.join(format!("agent-{:02}.md", i));
assert!(
tokio::fs::metadata(&agent_path).await.is_ok(),
"Agent {:02} should be installed",
i
);
}
Ok(())
}
#[tokio::test]
async fn test_concurrent_pattern_expansion() -> Result<()> {
agpm_cli::test_utils::init_test_logging(None);
let project = TestProject::new().await?;
let community_repo = project.create_source_repo("community").await?;
for i in 0..12 {
community_repo
.add_resource(
"agents",
&format!("utils/utility-{:02}", i),
format!(
r#"---
# Utility Agent {:02}
This is a utility agent in the utils directory.
---
"#,
i
)
.as_str(),
)
.await?;
}
for i in 0..5 {
community_repo
.add_resource(
"agents",
&format!("pattern-agent-{:02}", i),
r#"---
dependencies:
agents:
- path: ./utils/utility-*.md
version: v1.0.0
---
# Pattern Agent
This agent depends on all utility agents via pattern.
"#,
)
.await?;
}
community_repo.commit_all("Initial commit")?;
community_repo.tag_version("v1.0.0")?;
let source_url = community_repo.bare_file_url(project.sources_path()).await?;
let manifest = ManifestBuilder::new()
.add_source("community", &source_url)
.add_agent_pattern("all-utilities", "community", "agents/utils/utility-*.md", "v1.0.0")
.add_agent_pattern("pattern-agents", "community", "agents/pattern-agent-*.md", "v1.0.0")
.build();
project.write_manifest(&manifest).await?;
let output = project.run_agpm(&["install"])?;
assert!(output.success, "Install should succeed. Stderr: {}", output.stderr);
let agents_dir = project.project_path().join(".claude/agents/agpm");
for i in 0..12 {
let utility_path = agents_dir.join(format!("utility-{:02}.md", i));
assert!(
tokio::fs::metadata(&utility_path).await.is_ok(),
"Utility agent {:02} should be installed via pattern",
i
);
}
for i in 0..5 {
let agent_path = agents_dir.join(format!("pattern-agent-{:02}.md", i));
assert!(
tokio::fs::metadata(&agent_path).await.is_ok(),
"Pattern agent {:02} should be installed",
i
);
}
Ok(())
}
#[tokio::test]
async fn test_parallel_batch_calculation() -> Result<()> {
agpm_cli::test_utils::init_test_logging(None);
let project = TestProject::new().await?;
let community_repo = project.create_source_repo("community").await?;
for i in 0..25 {
community_repo
.add_resource(
"agents",
&format!("batch-test-{:02}", i),
r#"---
name: "Batch Test Agent"
---
# Batch Test Agent
This agent is part of batch processing tests.
"#,
)
.await?;
}
community_repo.commit_all("Initial commit")?;
community_repo.tag_version("v1.0.0")?;
let source_url = community_repo.bare_file_url(project.sources_path()).await?;
let mut builder = ManifestBuilder::new().add_source("community", &source_url);
for i in 0..25 {
builder = builder.add_standard_agent(
&format!("batch-test-{:02}", i),
"community",
&format!("agents/batch-test-{:02}.md", i),
);
}
let manifest = builder.build();
project.write_manifest(&manifest).await?;
let output = project.run_agpm(&["install", "--verbose"])?;
assert!(output.success, "Install should succeed. Stderr: {}", output.stderr);
let lockfile_content = project.read_lockfile().await?;
for i in 0..25 {
assert!(
lockfile_content.contains(&format!("batch-test-{:02}", i)),
"Batch test agent {:02} should be in lockfile",
i
);
}
Ok(())
}
#[tokio::test]
async fn test_concurrent_shared_dependencies() -> Result<()> {
agpm_cli::test_utils::init_test_logging(None);
let project = TestProject::new().await?;
let community_repo = project.create_source_repo("community").await?;
for i in 0..5 {
community_repo
.add_resource(
"agents",
&format!("shared-util-{:02}", i),
format!(
r#"---
# Shared Utility {:02}
This is a shared utility used by many agents.
---
"#,
i
)
.as_str(),
)
.await?;
}
for i in 0..15 {
community_repo
.add_resource(
"agents",
&format!("shared-agent-{:02}", i),
format!(
r#"---
dependencies:
agents:
- path: shared-util-{:02}.md
version: v1.0.0
- path: shared-util-{:02}.md
version: v1.0.0
---
# Shared Agent {:02}
This agent uses shared utilities.
"#,
i % 5,
(i + 1) % 5,
i
)
.as_str(),
)
.await?;
}
community_repo.commit_all("Initial commit")?;
community_repo.tag_version("v1.0.0")?;
let source_url = community_repo.bare_file_url(project.sources_path()).await?;
let mut builder = ManifestBuilder::new().add_source("community", &source_url);
for i in 0..15 {
builder = builder.add_standard_agent(
&format!("shared-agent-{:02}", i),
"community",
&format!("agents/shared-agent-{:02}.md", i),
);
}
let manifest = builder.build();
project.write_manifest(&manifest).await?;
let output = project.run_agpm(&["install"])?;
assert!(output.success, "Install should succeed. Stderr: {}", output.stderr);
let agents_dir = project.project_path().join(".claude/agents/agpm");
for i in 0..5 {
let util_path = agents_dir.join(format!("shared-util-{:02}.md", i));
assert!(
tokio::fs::metadata(&util_path).await.is_ok(),
"Shared utility {:02} should be installed",
i
);
}
for i in 0..15 {
let agent_path = agents_dir.join(format!("shared-agent-{:02}.md", i));
assert!(
tokio::fs::metadata(&agent_path).await.is_ok(),
"Shared agent {:02} should be installed",
i
);
}
Ok(())
}