re-uploading work
This commit is contained in:
494
crates/cli/tests/pack_registry_tests.rs
Normal file
494
crates/cli/tests/pack_registry_tests.rs
Normal file
@@ -0,0 +1,494 @@
|
||||
//! CLI integration tests for pack registry commands
|
||||
#![allow(deprecated)]
|
||||
|
||||
//!
|
||||
//! This module tests:
|
||||
//! - `attune pack install` command with all sources
|
||||
//! - `attune pack checksum` command
|
||||
//! - `attune pack index-entry` command
|
||||
//! - `attune pack index-update` command
|
||||
//! - `attune pack index-merge` command
|
||||
//! - Error handling and output formatting
|
||||
|
||||
use assert_cmd::Command;
|
||||
use predicates::prelude::*;
|
||||
use serde_json::Value;
|
||||
use std::fs;
|
||||
|
||||
use tempfile::TempDir;
|
||||
|
||||
/// Helper to create a test pack directory with pack.yaml
|
||||
fn create_test_pack(name: &str, version: &str, deps: &[&str]) -> TempDir {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
|
||||
let deps_yaml = if deps.is_empty() {
|
||||
"dependencies: []".to_string()
|
||||
} else {
|
||||
let dep_list = deps
|
||||
.iter()
|
||||
.map(|d| format!(" - {}", d))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
format!("dependencies:\n{}", dep_list)
|
||||
};
|
||||
|
||||
let pack_yaml = format!(
|
||||
r#"
|
||||
ref: {}
|
||||
name: Test Pack {}
|
||||
version: {}
|
||||
description: Test pack for CLI integration tests
|
||||
author: Test Author
|
||||
email: test@example.com
|
||||
license: Apache-2.0
|
||||
homepage: https://example.com
|
||||
repository: https://github.com/example/pack
|
||||
keywords:
|
||||
- test
|
||||
- cli
|
||||
{}
|
||||
python: "3.8"
|
||||
actions:
|
||||
test_action:
|
||||
entry_point: test.py
|
||||
runner_type: python-script
|
||||
description: Test action
|
||||
sensors:
|
||||
test_sensor:
|
||||
entry_point: sensor.py
|
||||
runner_type: python-script
|
||||
triggers:
|
||||
test_trigger:
|
||||
description: Test trigger
|
||||
"#,
|
||||
name, name, version, deps_yaml
|
||||
);
|
||||
|
||||
fs::write(temp_dir.path().join("pack.yaml"), pack_yaml).unwrap();
|
||||
fs::write(temp_dir.path().join("test.py"), "print('test action')").unwrap();
|
||||
fs::write(temp_dir.path().join("sensor.py"), "print('test sensor')").unwrap();
|
||||
|
||||
temp_dir
|
||||
}
|
||||
|
||||
/// Helper to create a registry index file
|
||||
fn create_test_index(packs: &[(&str, &str)]) -> TempDir {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
|
||||
let pack_entries: Vec<String> = packs
|
||||
.iter()
|
||||
.map(|(name, version)| {
|
||||
format!(
|
||||
r#"{{
|
||||
"ref": "{}",
|
||||
"label": "Test Pack {}",
|
||||
"version": "{}",
|
||||
"author": "Test",
|
||||
"license": "Apache-2.0",
|
||||
"keywords": ["test"],
|
||||
"install_sources": [
|
||||
{{
|
||||
"type": "git",
|
||||
"url": "https://github.com/test/{}.git",
|
||||
"ref": "v{}",
|
||||
"checksum": "sha256:abc123"
|
||||
}}
|
||||
]
|
||||
}}"#,
|
||||
name, name, version, name, version
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let index = format!(
|
||||
r#"{{
|
||||
"version": "1.0",
|
||||
"packs": [
|
||||
{}
|
||||
]
|
||||
}}"#,
|
||||
pack_entries.join(",\n")
|
||||
);
|
||||
|
||||
fs::write(temp_dir.path().join("index.json"), index).unwrap();
|
||||
|
||||
temp_dir
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_checksum_directory() {
|
||||
let pack_dir = create_test_pack("checksum-test", "1.0.0", &[]);
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("--output")
|
||||
.arg("table")
|
||||
.arg("pack")
|
||||
.arg("checksum")
|
||||
.arg(pack_dir.path().to_str().unwrap());
|
||||
|
||||
cmd.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("sha256:"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_checksum_json_output() {
|
||||
let pack_dir = create_test_pack("checksum-json", "1.0.0", &[]);
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("--output")
|
||||
.arg("json")
|
||||
.arg("pack")
|
||||
.arg("checksum")
|
||||
.arg(pack_dir.path().to_str().unwrap());
|
||||
|
||||
let output = cmd.assert().success();
|
||||
let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap();
|
||||
|
||||
// Verify it's valid JSON
|
||||
let json: Value = serde_json::from_str(&stdout).unwrap();
|
||||
assert!(json["checksum"].is_string());
|
||||
assert!(json["checksum"].as_str().unwrap().starts_with("sha256:"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_checksum_nonexistent_path() {
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("pack").arg("checksum").arg("/nonexistent/path");
|
||||
|
||||
cmd.assert().failure().stderr(
|
||||
predicate::str::contains("not found").or(predicate::str::contains("does not exist")),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_index_entry_generates_valid_json() {
|
||||
let pack_dir = create_test_pack("index-entry-test", "1.2.3", &[]);
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("--output")
|
||||
.arg("json")
|
||||
.arg("pack")
|
||||
.arg("index-entry")
|
||||
.arg(pack_dir.path().to_str().unwrap())
|
||||
.arg("--git-url")
|
||||
.arg("https://github.com/test/pack.git")
|
||||
.arg("--git-ref")
|
||||
.arg("v1.2.3");
|
||||
|
||||
let output = cmd.assert().success();
|
||||
let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap();
|
||||
|
||||
// Verify it's valid JSON
|
||||
let json: Value = serde_json::from_str(&stdout).unwrap();
|
||||
assert_eq!(json["ref"], "index-entry-test");
|
||||
assert_eq!(json["version"], "1.2.3");
|
||||
assert!(json["install_sources"].is_array());
|
||||
assert!(json["install_sources"][0]["checksum"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.starts_with("sha256:"));
|
||||
|
||||
// Verify metadata
|
||||
assert_eq!(json["author"], "Test Author");
|
||||
assert_eq!(json["license"], "Apache-2.0");
|
||||
assert!(json["keywords"].as_array().unwrap().len() > 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_index_entry_with_archive_url() {
|
||||
let pack_dir = create_test_pack("archive-test", "2.0.0", &[]);
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("--output")
|
||||
.arg("json")
|
||||
.arg("pack")
|
||||
.arg("index-entry")
|
||||
.arg(pack_dir.path().to_str().unwrap())
|
||||
.arg("--archive-url")
|
||||
.arg("https://releases.example.com/pack-2.0.0.tar.gz");
|
||||
|
||||
let output = cmd.assert().success();
|
||||
let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap();
|
||||
|
||||
let json: Value = serde_json::from_str(&stdout).unwrap();
|
||||
assert!(json["install_sources"].as_array().unwrap().len() > 0);
|
||||
|
||||
let archive_source = &json["install_sources"][0];
|
||||
assert_eq!(archive_source["type"], "archive");
|
||||
assert_eq!(
|
||||
archive_source["url"],
|
||||
"https://releases.example.com/pack-2.0.0.tar.gz"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_index_entry_missing_pack_yaml() {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
fs::write(temp_dir.path().join("readme.txt"), "No pack.yaml here").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("pack")
|
||||
.arg("index-entry")
|
||||
.arg(temp_dir.path().to_str().unwrap());
|
||||
|
||||
cmd.assert()
|
||||
.failure()
|
||||
.stderr(predicate::str::contains("pack.yaml"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_index_update_adds_new_entry() {
|
||||
let index_dir = create_test_index(&[("existing-pack", "1.0.0")]);
|
||||
let index_path = index_dir.path().join("index.json");
|
||||
|
||||
let pack_dir = create_test_pack("new-pack", "1.0.0", &[]);
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("pack")
|
||||
.arg("index-update")
|
||||
.arg("--index")
|
||||
.arg(index_path.to_str().unwrap())
|
||||
.arg(pack_dir.path().to_str().unwrap())
|
||||
.arg("--git-url")
|
||||
.arg("https://github.com/test/new-pack.git")
|
||||
.arg("--git-ref")
|
||||
.arg("v1.0.0");
|
||||
|
||||
cmd.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("new-pack"))
|
||||
.stdout(predicate::str::contains("1.0.0"));
|
||||
|
||||
// Verify index was updated
|
||||
let updated_index = fs::read_to_string(&index_path).unwrap();
|
||||
let json: Value = serde_json::from_str(&updated_index).unwrap();
|
||||
assert_eq!(json["packs"].as_array().unwrap().len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_index_update_prevents_duplicate_without_flag() {
|
||||
let index_dir = create_test_index(&[("existing-pack", "1.0.0")]);
|
||||
let index_path = index_dir.path().join("index.json");
|
||||
|
||||
let pack_dir = create_test_pack("existing-pack", "1.0.0", &[]);
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("pack")
|
||||
.arg("index-update")
|
||||
.arg("--index")
|
||||
.arg(index_path.to_str().unwrap())
|
||||
.arg(pack_dir.path().to_str().unwrap())
|
||||
.arg("--git-url")
|
||||
.arg("https://github.com/test/existing-pack.git");
|
||||
|
||||
cmd.assert()
|
||||
.failure()
|
||||
.stderr(predicate::str::contains("already exists"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_index_update_with_update_flag() {
|
||||
let index_dir = create_test_index(&[("existing-pack", "1.0.0")]);
|
||||
let index_path = index_dir.path().join("index.json");
|
||||
|
||||
let pack_dir = create_test_pack("existing-pack", "2.0.0", &[]);
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("pack")
|
||||
.arg("index-update")
|
||||
.arg("--index")
|
||||
.arg(index_path.to_str().unwrap())
|
||||
.arg(pack_dir.path().to_str().unwrap())
|
||||
.arg("--git-url")
|
||||
.arg("https://github.com/test/existing-pack.git")
|
||||
.arg("--git-ref")
|
||||
.arg("v2.0.0")
|
||||
.arg("--update");
|
||||
|
||||
cmd.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("existing-pack"))
|
||||
.stdout(predicate::str::contains("2.0.0"));
|
||||
|
||||
// Verify version was updated
|
||||
let updated_index = fs::read_to_string(&index_path).unwrap();
|
||||
let json: Value = serde_json::from_str(&updated_index).unwrap();
|
||||
let packs = json["packs"].as_array().unwrap();
|
||||
assert_eq!(packs.len(), 1);
|
||||
assert_eq!(packs[0]["version"], "2.0.0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_index_update_invalid_index_file() {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
let bad_index = temp_dir.path().join("bad-index.json");
|
||||
fs::write(&bad_index, "not valid json {").unwrap();
|
||||
|
||||
let pack_dir = create_test_pack("test-pack", "1.0.0", &[]);
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("pack")
|
||||
.arg("index-update")
|
||||
.arg("--index")
|
||||
.arg(bad_index.to_str().unwrap())
|
||||
.arg(pack_dir.path().to_str().unwrap());
|
||||
|
||||
cmd.assert().failure();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_index_merge_combines_indexes() {
|
||||
let index1 = create_test_index(&[("pack-a", "1.0.0"), ("pack-b", "1.0.0")]);
|
||||
let index2 = create_test_index(&[("pack-c", "1.0.0"), ("pack-d", "1.0.0")]);
|
||||
|
||||
let output_dir = TempDir::new().unwrap();
|
||||
let output_path = output_dir.path().join("merged.json");
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("pack")
|
||||
.arg("index-merge")
|
||||
.arg("--file")
|
||||
.arg(output_path.to_str().unwrap())
|
||||
.arg(index1.path().join("index.json").to_str().unwrap())
|
||||
.arg(index2.path().join("index.json").to_str().unwrap());
|
||||
|
||||
cmd.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("Merged"))
|
||||
.stdout(predicate::str::contains("2"));
|
||||
|
||||
// Verify merged file
|
||||
let merged_content = fs::read_to_string(&output_path).unwrap();
|
||||
let json: Value = serde_json::from_str(&merged_content).unwrap();
|
||||
assert_eq!(json["packs"].as_array().unwrap().len(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_index_merge_deduplicates() {
|
||||
let index1 = create_test_index(&[("pack-a", "1.0.0"), ("pack-b", "1.0.0")]);
|
||||
let index2 = create_test_index(&[("pack-a", "2.0.0"), ("pack-c", "1.0.0")]);
|
||||
|
||||
let output_dir = TempDir::new().unwrap();
|
||||
let output_path = output_dir.path().join("merged.json");
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("pack")
|
||||
.arg("index-merge")
|
||||
.arg("--file")
|
||||
.arg(output_path.to_str().unwrap())
|
||||
.arg(index1.path().join("index.json").to_str().unwrap())
|
||||
.arg(index2.path().join("index.json").to_str().unwrap());
|
||||
|
||||
cmd.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("Duplicates resolved"));
|
||||
|
||||
// Verify deduplication (should have 3 unique packs: pack-a, pack-b, pack-c)
|
||||
let merged_content = fs::read_to_string(&output_path).unwrap();
|
||||
let json: Value = serde_json::from_str(&merged_content).unwrap();
|
||||
let packs = json["packs"].as_array().unwrap();
|
||||
assert_eq!(packs.len(), 3);
|
||||
|
||||
// Verify pack-a has the newer version
|
||||
let pack_a = packs.iter().find(|p| p["ref"] == "pack-a").unwrap();
|
||||
assert_eq!(pack_a["version"], "2.0.0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_index_merge_output_exists_without_force() {
|
||||
let index1 = create_test_index(&[("pack-a", "1.0.0")]);
|
||||
|
||||
let output_dir = TempDir::new().unwrap();
|
||||
let output_path = output_dir.path().join("merged.json");
|
||||
fs::write(&output_path, "existing content").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("pack")
|
||||
.arg("index-merge")
|
||||
.arg("--file")
|
||||
.arg(output_path.to_str().unwrap())
|
||||
.arg(index1.path().join("index.json").to_str().unwrap());
|
||||
|
||||
cmd.assert()
|
||||
.failure()
|
||||
.stderr(predicate::str::contains("already exists").or(predicate::str::contains("force")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_index_merge_with_force_flag() {
|
||||
let index1 = create_test_index(&[("pack-a", "1.0.0")]);
|
||||
|
||||
let output_dir = TempDir::new().unwrap();
|
||||
let output_path = output_dir.path().join("merged.json");
|
||||
fs::write(&output_path, "existing content").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("pack")
|
||||
.arg("index-merge")
|
||||
.arg("--file")
|
||||
.arg(output_path.to_str().unwrap())
|
||||
.arg(index1.path().join("index.json").to_str().unwrap())
|
||||
.arg("--force");
|
||||
|
||||
cmd.assert().success();
|
||||
|
||||
// Verify file was overwritten
|
||||
let merged_content = fs::read_to_string(&output_path).unwrap();
|
||||
assert_ne!(merged_content, "existing content");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_index_merge_empty_input_list() {
|
||||
let output_dir = TempDir::new().unwrap();
|
||||
let output_path = output_dir.path().join("merged.json");
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("pack")
|
||||
.arg("index-merge")
|
||||
.arg("--file")
|
||||
.arg(output_path.to_str().unwrap());
|
||||
|
||||
// Should fail due to missing required inputs
|
||||
cmd.assert().failure();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_index_merge_missing_input_file() {
|
||||
let index1 = create_test_index(&[("pack-a", "1.0.0")]);
|
||||
let output_dir = TempDir::new().unwrap();
|
||||
let output_path = output_dir.path().join("merged.json");
|
||||
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
cmd.arg("pack")
|
||||
.arg("index-merge")
|
||||
.arg("--file")
|
||||
.arg(output_path.to_str().unwrap())
|
||||
.arg(index1.path().join("index.json").to_str().unwrap())
|
||||
.arg("/nonexistent/index.json");
|
||||
|
||||
// Should succeed but skip missing file (with warning in stderr)
|
||||
cmd.assert()
|
||||
.success()
|
||||
.stderr(predicate::str::contains("Skipping").or(predicate::str::contains("missing")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pack_commands_help() {
|
||||
let commands = vec![
|
||||
vec!["pack", "checksum", "--help"],
|
||||
vec!["pack", "index-entry", "--help"],
|
||||
vec!["pack", "index-update", "--help"],
|
||||
vec!["pack", "index-merge", "--help"],
|
||||
];
|
||||
|
||||
for args in commands {
|
||||
let mut cmd = Command::cargo_bin("attune").unwrap();
|
||||
for arg in &args {
|
||||
cmd.arg(arg);
|
||||
}
|
||||
cmd.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("Usage:"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user