Menu
AkurAI-Build
publicLatest change 7255093e06e11217a8aa00ce4b6f336d3a5fa654 - Add named service identities and akurai_repo_protect by Ólafur Búi Ólafsson
#[path = "support/mcp.rs"]
mod support;
use std::{fs, path::Path, process::Command};
use anyhow::{Context, Result, ensure};
use serde_json::{Value, json};
use support::McpSession;
/// Verify the MCP tool set produces valid results across a full lifecycle:
/// bootstrap via the remaining CLI subcommands, then repository and query
/// tools over stdio.
#[test]
fn mcp_json_contract_across_lifecycle() -> Result<()> {
let work = tempfile::tempdir()?;
let data = work.path().join("data");
let key = work.path().join("key.bin");
let repo = work.path().join("repo");
fs::create_dir(&repo)?;
// init a bare git repo
let init = Command::new("git")
.arg("init")
.args(["-b", "main"])
.arg(&repo)
.output()?;
ensure!(init.status.success(), "git init failed");
// keygen and migrate remain plain CLI subcommands.
let out = cli(&data, &key, &["keygen", "--out", support::str(&key)?])?;
assert!(out["ok"] == true, "keygen envelope: {out}");
assert!(out["data"]["created"] == true, "key should be created");
let out = cli(&data, &key, &["migrate"])?;
assert!(out["ok"] == true, "migrate envelope: {out}");
assert!(
out["data"]["migrations_applied"]
.as_i64()
.is_some_and(|n| n >= 0),
"migrate should report applied count"
);
let mut mcp = McpSession::start(&data, &key, false)?;
let added = mcp.call(
"akurai_repo_add",
json!({"name": "test-app", "url": support::str(&repo)?, "branch": "main"}),
)?;
assert_eq!(added["name"], "test-app");
let repos = mcp.call("akurai_repo_list", json!({}))?;
let repos = repos.as_array().context("repo list should be array")?;
assert_eq!(repos.len(), 1);
let workers = mcp.call("akurai_workers", json!({}))?;
let workers = workers.as_array().context("workers should be array")?;
assert!(workers.is_empty(), "no workers registered yet");
let runs = mcp.call("akurai_runs", json!({}))?;
let runs = runs.as_array().context("runs should be an array")?;
assert!(runs.is_empty(), "no runs executed yet");
let renamed = mcp.call(
"akurai_repo_rename",
json!({"old": "test-app", "new": "test-app-2"}),
)?;
assert_eq!(renamed["name"], "test-app-2");
let visibility = mcp.call(
"akurai_repo_visibility",
json!({"repository": "test-app-2", "visibility": "public"}),
)?;
assert_eq!(visibility["visibility"], "public");
let protected = mcp.call(
"akurai_repo_protect",
json!({"repository": "test-app-2", "protected": true, "owner": "reviewer"}),
)?;
assert_eq!(protected["protect_default_branch"], true);
assert_eq!(protected["owner_sub"], "reviewer");
let error = mcp.call_error("akurai_repo_list", json!({"unknown_field": true}))?;
assert!(
!error.is_empty(),
"unknown-field call should report an error"
);
Ok(())
}
/// Run the CLI expecting success and return parsed JSON.
fn cli(data: &Path, key: &Path, arguments: &[&str]) -> Result<Value> {
let output = Command::new(env!("CARGO_BIN_EXE_akurai"))
.args([
"--data",
support::str(data)?,
"--key-file",
support::str(key)?,
])
.args(arguments)
.output()?;
let value: Value = serde_json::from_slice(&output.stdout).with_context(|| {
format!(
"invalid CLI JSON: {}",
String::from_utf8_lossy(&output.stdout)
)
})?;
ensure!(
output.status.success(),
"CLI failed ({value}): {}",
String::from_utf8_lossy(&output.stderr)
);
Ok(value)
}