use rivox::adapters::EcosystemAdapter;
use rivox::adapters::go::GoAdapter;
use rivox::adapters::gradle::GradleAdapter;
use rivox::adapters::python::PythonAdapter;
use rivox::cache::distributed::{CasEndpoint, DistributedCas};
use rivox::cache::local::LocalCas;
use rivox::cache::reapi::ReapiClient;
use rivox::cache::reapi_exec::{
ActionSpec, CommandSpec, DigestVal, ExecuteRequest, ReapiExecClient,
};
use rivox::cache::remote_worker::RemoteWorker;
use rivox::conformance::suite::ConformanceSuite;
use rivox::graph::GraphNode;
use rivox::graph::builder::UnifiedGraph;
use rivox::graph::diff::diff_graphs;
use rivox::graph::scheduler::Scheduler;
use rivox::oci::OciBuilder;
use rivox::policy::{PolicyEngine, PolicyStatus};
use rivox::provenance::sigstore::sign_and_register_rekor;
use rivox::sandbox::get_default_sandbox;
use sha2::Digest;
use std::collections::HashMap;
use std::fs;
use tempfile::tempdir;
#[test]
fn test_python_conformance_equivalence() {
let _adapter = PythonAdapter;
let nodes1 = vec![GraphNode {
ecosystem: "python".to_string(),
package_name: "torch".to_string(),
resolved_version: "2.1.0".to_string(),
content_hash: "sha256:1234".to_string(),
platform_markers: None,
lock_ref: "uv.lock".to_string(),
}];
let nodes2 = nodes1.clone();
assert!(ConformanceSuite::verify_equivalence(&nodes1, &nodes2).is_ok());
}
#[test]
fn test_go_adapter_lockfile_parse() {
let dir = tempdir().unwrap();
let lock_path = dir.path().join("go.sum");
let content = "github.com/gin-gonic/gin v1.9.1 h1:4AAgXAIGfrXH3vXWyzBdp1pCMRamkpDQM3vSOAQDA38=\ngithub.com/gin-gonic/gin v1.9.1/go.mod h1:h4dYUFRTXIZoSlKGbyKj0nZzF7w0B+1K1J4F3vSOAQDA38=\n";
fs::write(&lock_path, content).unwrap();
let adapter = GoAdapter;
let nodes = adapter.parse_lockfile(&lock_path).unwrap();
assert_eq!(nodes.len(), 1);
assert_eq!(nodes[0].package_name, "github.com/gin-gonic/gin");
assert_eq!(nodes[0].resolved_version, "v1.9.1");
}
#[test]
fn test_gradle_adapter_lockfile_parse() {
let dir = tempdir().unwrap();
let lock_path = dir.path().join("gradle.lockfile");
let content = "# This is a Gradle lockfile\norg.springframework.boot:spring-boot-starter-web:3.2.0=compileClasspath\n";
fs::write(&lock_path, content).unwrap();
let adapter = GradleAdapter;
let nodes = adapter.parse_lockfile(&lock_path).unwrap();
assert_eq!(nodes.len(), 1);
assert_eq!(
nodes[0].package_name,
"org.springframework.boot:spring-boot-starter-web"
);
assert_eq!(nodes[0].resolved_version, "3.2.0");
}
#[test]
fn test_cas_prune_and_integrity() {
let cas = LocalCas::new().unwrap();
let dir = tempdir().unwrap();
let test_file = dir.path().join("test.txt");
fs::write(&test_file, "rivox content addressing").unwrap();
let hash = "sha256:7798934526d11a7c413e1fb64c483d3126f58204689b142750faec899b821ee5";
assert!(cas.store_file(hash, &test_file).is_ok());
assert!(cas.has_blob(hash));
let _pruned = cas.prune(30).unwrap();
}
#[tokio::test]
async fn test_reapi_client_validation() {
let client = ReapiClient::new("http://localhost:8980".to_string());
let blob = b"hello reapi".to_vec();
let hash = format!("sha256:{}", hex::encode(sha2::Sha256::digest(&blob)));
let result = client.upload_blobs(vec![(hash, blob)]).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_reapi_exec_client() {
let client = ReapiExecClient::new("http://localhost:8980".to_string());
let command = CommandSpec {
arguments: vec!["cargo".to_string(), "--version".to_string()],
environment_variables: HashMap::new(),
output_files: vec![],
output_directories: vec![],
};
let command_bytes = serde_json::to_vec(&command).unwrap();
let command_digest = ReapiExecClient::compute_digest(&command_bytes);
let action = ActionSpec {
command_digest: command_digest.clone(),
input_root_digest: DigestVal {
hash: "sha256:0000000000000000000000000000000000000000000000000000000000000000"
.to_string(),
size_bytes: 0,
},
timeout_seconds: 60,
};
let action_bytes = serde_json::to_vec(&action).unwrap();
let action_digest = ReapiExecClient::compute_digest(&action_bytes);
let req = ExecuteRequest {
action_digest,
skip_cache_lookup: true,
instance_name: "test".to_string(),
};
let resp = client
.execute_action(&req, &action, &command)
.await
.unwrap();
assert_eq!(resp.status_code, 0);
}
#[test]
fn test_remote_worker_path_traversal_rejection() {
assert!(RemoteWorker::validate_path_security("valid/path.txt").is_ok());
assert!(RemoteWorker::validate_path_security("../escape.txt").is_err());
assert!(RemoteWorker::validate_path_security("/absolute/escape").is_err());
}
#[test]
fn test_distributed_cas_replication() {
let local_cas = LocalCas::new().unwrap();
let endpoints = vec![CasEndpoint {
name: "primary".to_string(),
url: "http://cas-primary.internal".to_string(),
is_healthy: true,
priority: 1,
}];
let dist_cas = DistributedCas::new(local_cas, endpoints);
let dir = tempdir().unwrap();
let test_file = dir.path().join("dist_test.txt");
let content = b"distributed cas artifact";
fs::write(&test_file, content).unwrap();
let hash = format!("sha256:{}", hex::encode(sha2::Sha256::digest(content)));
assert!(dist_cas.store_blob_with_failover(&hash, &test_file).is_ok());
}
#[test]
fn test_oci_builder_layout() {
let dir = tempdir().unwrap();
let output_dir = dir.path().join("oci_dist");
let layout_dir = OciBuilder::build_oci_layout(&output_dir, "test_app", &[]).unwrap();
assert!(layout_dir.join("oci-layout").exists());
assert!(layout_dir.join("index.json").exists());
assert!(layout_dir.join("blobs").join("sha256").exists());
}
#[test]
fn test_graph_diff_computation() {
let node_old = GraphNode {
ecosystem: "python".to_string(),
package_name: "requests".to_string(),
resolved_version: "2.28.0".to_string(),
content_hash: "sha256:1111".to_string(),
platform_markers: None,
lock_ref: "uv.lock".to_string(),
};
let node_new = GraphNode {
ecosystem: "python".to_string(),
package_name: "requests".to_string(),
resolved_version: "2.31.0".to_string(),
content_hash: "sha256:2222".to_string(),
platform_markers: None,
lock_ref: "uv.lock".to_string(),
};
let diff = diff_graphs(&[node_old], &[node_new]);
assert_eq!(diff.changed.len(), 1);
assert!(diff.rebuild_required);
}
#[test]
fn test_policy_engine_enforcement() {
let engine = PolicyEngine::new(rivox::policy::PolicyConfig::default());
let allowed_node = GraphNode {
ecosystem: "python".to_string(),
package_name: "numpy".to_string(),
resolved_version: "1.24.0".to_string(),
content_hash: "sha256:abc".to_string(),
platform_markers: None,
lock_ref: "uv.lock".to_string(),
};
let res = engine.evaluate_graph(&[allowed_node]);
assert_eq!(res.status, PolicyStatus::Pass);
}
#[test]
fn test_sandbox_default_executor() {
let sandbox = get_default_sandbox();
assert!(!sandbox.name().is_empty());
}
#[test]
fn test_scheduler_wavefront_levels() {
let mut graph = UnifiedGraph::new();
let node1 = GraphNode {
ecosystem: "python".to_string(),
package_name: "base".to_string(),
resolved_version: "1.0".to_string(),
content_hash: "sha256:1".to_string(),
platform_markers: None,
lock_ref: "uv.lock".to_string(),
};
let node2 = GraphNode {
ecosystem: "rust".to_string(),
package_name: "ext".to_string(),
resolved_version: "0.1".to_string(),
content_hash: "sha256:2".to_string(),
platform_markers: None,
lock_ref: "Cargo.lock".to_string(),
};
graph.add_nodes(vec![node1, node2]);
let wavefronts = Scheduler::plan_wavefronts(&graph).unwrap();
assert!(!wavefronts.is_empty());
}
#[test]
fn test_sigstore_rekor_attestation() {
let statement = serde_json::json!({
"buildType": "https://rivox.dev/attestations/v1",
"subject": [{"name": "rivox-binary", "digest": {"sha256": "123456"}}]
});
let rekor_ref = sign_and_register_rekor(&statement).unwrap();
assert!(rekor_ref.is_some());
assert!(rekor_ref.unwrap().starts_with("rekor:"));
}