use anyhow::Result;
use std::{fs, time::Duration};
use tokio::time::Instant;
mod common;
use common::TestProject;
#[tokio::test]
async fn test_instance_cache_reuse() -> Result<()> {
let project = TestProject::new()?;
let source_repo = project.create_source_repo("official")?;
source_repo.add_resource("agents", "agent-1", "# Agent 1\n\nTest agent 1")?;
source_repo.add_resource("agents", "agent-2", "# Agent 2\n\nTest agent 2")?;
source_repo.add_resource("agents", "agent-3", "# Agent 3\n\nTest agent 3")?;
source_repo.commit_all("Add test agents")?;
source_repo.tag_version("v1.0.0")?;
let source_url = source_repo.bare_file_url(project.sources_path())?;
let manifest_content = format!(
r#"
[sources]
official = "{}"
[agents]
agent1 = {{ source = "official", path = "agents/agent-1.md", version = "v1.0.0" }}
agent2 = {{ source = "official", path = "agents/agent-2.md", version = "v1.0.0" }}
agent3 = {{ source = "official", path = "agents/agent-3.md", version = "v1.0.0" }}
"#,
source_url
);
project.write_manifest(&manifest_content)?;
let start = Instant::now();
let output = project.run_ccpm(&["install"])?;
output.assert_success();
let first_duration = start.elapsed();
fs::remove_dir_all(project.project_path().join(".claude"))?;
let start = Instant::now();
let output = project.run_ccpm(&["install"])?;
output.assert_success();
let second_duration = start.elapsed();
assert!(
second_duration <= first_duration + Duration::from_millis(500),
"Second install should reuse cache and be comparable in speed. First: {:?}, Second: {:?}",
first_duration,
second_duration
);
assert!(
project
.project_path()
.join(".claude/agents/agent1.md")
.exists()
);
assert!(
project
.project_path()
.join(".claude/agents/agent2.md")
.exists()
);
assert!(
project
.project_path()
.join(".claude/agents/agent3.md")
.exists()
);
Ok(())
}
#[tokio::test]
async fn test_fetch_caching_prevents_redundancy() -> Result<()> {
let project = TestProject::new()?;
let source_repo = project.create_source_repo("official")?;
source_repo.add_resource(
"agents",
"fetch-agent-1",
"# Fetch Agent 1\n\nTest fetch agent 1",
)?;
source_repo.add_resource(
"agents",
"fetch-agent-2",
"# Fetch Agent 2\n\nTest fetch agent 2",
)?;
source_repo.add_resource(
"snippets",
"fetch-snippet-1",
"# Fetch Snippet 1\n\nTest fetch snippet 1",
)?;
source_repo.commit_all("Add test resources")?;
source_repo.tag_version("v1.0.0")?;
let source_url = source_repo.bare_file_url(project.sources_path())?;
let manifest_content = format!(
r#"
[sources]
official = "{}"
[agents]
agent1 = {{ source = "official", path = "agents/fetch-agent-1.md", version = "v1.0.0" }}
agent2 = {{ source = "official", path = "agents/fetch-agent-2.md", version = "v1.0.0" }}
[snippets]
snippet1 = {{ source = "official", path = "snippets/fetch-snippet-1.md", version = "v1.0.0" }}
"#,
source_url
);
project.write_manifest(&manifest_content)?;
let start = Instant::now();
let output = project.run_ccpm(&["install", "--verbose"])?;
output.assert_success();
let duration = start.elapsed();
assert!(
duration < Duration::from_secs(30),
"Install with fetch caching should complete in under 30 seconds, took {:?}",
duration
);
assert!(
project
.project_path()
.join(".claude/agents/agent1.md")
.exists()
);
assert!(
project
.project_path()
.join(".claude/agents/agent2.md")
.exists()
);
assert!(
project
.project_path()
.join(".claude/ccpm/snippets/snippet1.md")
.exists()
);
Ok(())
}
#[tokio::test]
async fn test_cache_high_concurrency() -> Result<()> {
let project = TestProject::new()?;
let source_repo = project.create_source_repo("official")?;
for i in 0..20 {
source_repo.add_resource(
"agents",
&format!("concurrent-agent-{:02}", i),
&format!("# Concurrent Agent {:02}\n\nTest concurrent agent {}", i, i),
)?;
}
source_repo.commit_all("Add concurrent test agents")?;
source_repo.tag_version("v1.0.0")?;
let source_url = source_repo.bare_file_url(project.sources_path())?;
let mut manifest_content = format!(
r#"
[sources]
official = "{}"
[agents]
"#,
source_url
);
for i in 0..20 {
manifest_content.push_str(&format!(
"agent{:02} = {{ source = \"official\", path = \"agents/concurrent-agent-{:02}.md\", version = \"v1.0.0\" }}\n",
i, i
));
}
project.write_manifest(&manifest_content)?;
let start = Instant::now();
let output = project.run_ccpm(&["install"])?;
output.assert_success();
let duration = start.elapsed();
println!("High concurrency install took: {:?}", duration);
for i in 0..20 {
let agent_path = project
.project_path()
.join(format!(".claude/agents/agent{:02}.md", i));
assert!(agent_path.exists(), "Agent {} should be installed", i);
}
Ok(())
}
#[tokio::test]
async fn test_cache_persistence() -> Result<()> {
let project = TestProject::new()?;
let source_repo = project.create_source_repo("official")?;
source_repo.add_resource(
"agents",
"persistent-agent",
"# Persistent Agent\n\nTest persistent agent",
)?;
source_repo.add_resource(
"snippets",
"persistent-snippet",
"# Persistent Snippet\n\nTest persistent snippet",
)?;
source_repo.commit_all("Add persistent test resources")?;
source_repo.tag_version("v1.0.0")?;
let source_url = source_repo.bare_file_url(project.sources_path())?;
let manifest_content = format!(
r#"
[sources]
official = "{}"
[agents]
agent = {{ source = "official", path = "agents/persistent-agent.md", version = "v1.0.0" }}
[snippets]
snippet = {{ source = "official", path = "snippets/persistent-snippet.md", version = "v1.0.0" }}
"#,
source_url
);
project.write_manifest(&manifest_content)?;
let output = project.run_ccpm(&["install"])?;
output.assert_success();
let output = project.run_ccpm(&["update"])?;
output.assert_success();
let output = project.run_ccpm(&["list"])?;
output.assert_success();
assert!(
project
.project_path()
.join(".claude/agents/agent.md")
.exists()
);
assert!(
project
.project_path()
.join(".claude/ccpm/snippets/snippet.md")
.exists()
);
Ok(())
}