mod common;
use common::run_lua;
use wiremock::matchers::{header, method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};
#[tokio::test]
async fn test_argocd_client_creation() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/version"))
.and(header("Authorization", "Bearer test-token-123"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"Version": "v2.10.0",
"BuildDate": "2024-01-15T00:00:00Z",
"GitCommit": "abc123"
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}", {{ token = "test-token-123" }})
local v = c:version()
assert.eq(v.Version, "v2.10.0")
assert.eq(v.GitCommit, "abc123")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_basic_auth() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/version"))
.and(header("Authorization", "Basic YWRtaW46cGFzc3dvcmQ="))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"Version": "v2.10.0"
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}", {{ username = "admin", password = "password" }})
local v = c:version()
assert.eq(v.Version, "v2.10.0")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_applications_list() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/applications"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {},
"items": [
{
"metadata": {"name": "guestbook", "namespace": "argocd"},
"spec": {"project": "default", "source": {"repoURL": "https://github.com/example/repo"}},
"status": {
"health": {"status": "Healthy"},
"sync": {"status": "Synced"}
}
},
{
"metadata": {"name": "my-app", "namespace": "argocd"},
"spec": {"project": "production", "source": {"repoURL": "https://github.com/example/app"}},
"status": {
"health": {"status": "Degraded"},
"sync": {"status": "OutOfSync"}
}
}
]
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local apps = c.apps:list()
assert.eq(#apps, 2)
assert.eq(apps[1].metadata.name, "guestbook")
assert.eq(apps[1].status.health.status, "Healthy")
assert.eq(apps[2].metadata.name, "my-app")
assert.eq(apps[2].status.sync.status, "OutOfSync")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_application_get() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/applications/guestbook"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {"name": "guestbook", "namespace": "argocd", "uid": "abc-123"},
"spec": {
"project": "default",
"source": {
"repoURL": "https://github.com/argoproj/argocd-example-apps",
"path": "guestbook",
"targetRevision": "HEAD"
},
"destination": {
"server": "https://kubernetes.default.svc",
"namespace": "default"
}
},
"status": {
"health": {"status": "Healthy", "message": "All resources healthy"},
"sync": {"status": "Synced", "revision": "abc123def"}
}
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local app = c.apps:get("guestbook")
assert.eq(app.metadata.name, "guestbook")
assert.eq(app.metadata.uid, "abc-123")
assert.eq(app.spec.source.path, "guestbook")
assert.eq(app.status.health.status, "Healthy")
assert.eq(app.status.sync.revision, "abc123def")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_app_health() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/applications/guestbook"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {"name": "guestbook"},
"spec": {"project": "default"},
"status": {
"health": {"status": "Degraded", "message": "Pod crash loop"},
"sync": {"status": "Synced"}
}
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local h = c.apps:health("guestbook")
assert.eq(h.status, "Degraded")
assert.eq(h.sync, "Synced")
assert.eq(h.message, "Pod crash loop")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_sync() {
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/api/v1/applications/guestbook/sync"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {"name": "guestbook"},
"spec": {"project": "default"},
"status": {
"operationState": {
"phase": "Running",
"message": "Sync in progress",
"syncResult": {
"revision": "def456"
}
}
}
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local result = c.apps:sync("guestbook", {{ revision = "def456", prune = true }})
assert.eq(result.status.operationState.phase, "Running")
assert.eq(result.status.operationState.syncResult.revision, "def456")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_refresh() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/applications/guestbook"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {"name": "guestbook"},
"spec": {"project": "default"},
"status": {
"health": {"status": "Healthy"},
"sync": {"status": "Synced", "revision": "latest123"}
}
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local app = c.apps:refresh("guestbook", {{ type = "hard" }})
assert.eq(app.metadata.name, "guestbook")
assert.eq(app.status.sync.revision, "latest123")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_rollback() {
let server = MockServer::start().await;
Mock::given(method("PUT"))
.and(path("/api/v1/applications/guestbook/rollback"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {"name": "guestbook"},
"status": {
"operationState": {
"phase": "Succeeded",
"message": "Rollback complete"
}
}
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local result = c.apps:rollback("guestbook", 5)
assert.eq(result.status.operationState.phase, "Succeeded")
assert.eq(result.status.operationState.message, "Rollback complete")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_app_resources() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/applications/guestbook/resource-tree"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"nodes": [
{
"group": "apps",
"version": "v1",
"kind": "Deployment",
"name": "guestbook-ui",
"namespace": "default",
"health": {"status": "Healthy"}
},
{
"group": "",
"version": "v1",
"kind": "Service",
"name": "guestbook-ui",
"namespace": "default",
"health": {"status": "Healthy"}
}
]
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local tree = c.apps:resources("guestbook")
assert.eq(#tree.nodes, 2)
assert.eq(tree.nodes[1].kind, "Deployment")
assert.eq(tree.nodes[1].name, "guestbook-ui")
assert.eq(tree.nodes[2].kind, "Service")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_app_manifests() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/applications/guestbook/manifests"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"manifests": [
"{\"apiVersion\":\"v1\",\"kind\":\"Service\"}",
"{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\"}"
],
"revision": "abc123"
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local result = c.apps:manifests("guestbook")
assert.eq(#result.manifests, 2)
assert.eq(result.revision, "abc123")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_delete_app() {
let server = MockServer::start().await;
Mock::given(method("DELETE"))
.and(path("/api/v1/applications/guestbook"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {"name": "guestbook"},
"spec": {"project": "default"}
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local result = c.apps:delete("guestbook", {{ cascade = true, propagation_policy = "foreground" }})
assert.eq(result.metadata.name, "guestbook")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_projects_list() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/projects"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {},
"items": [
{
"metadata": {"name": "default"},
"spec": {
"description": "Default project",
"sourceRepos": ["*"],
"destinations": [{"server": "*", "namespace": "*"}]
}
},
{
"metadata": {"name": "production"},
"spec": {
"description": "Production apps",
"sourceRepos": ["https://github.com/myorg/*"],
"destinations": [{"server": "https://prod-cluster", "namespace": "prod"}]
}
}
]
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local projects = c.projects:list()
assert.eq(#projects, 2)
assert.eq(projects[1].metadata.name, "default")
assert.eq(projects[1].spec.description, "Default project")
assert.eq(projects[2].metadata.name, "production")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_project_get() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/projects/default"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {"name": "default"},
"spec": {
"description": "Default project",
"sourceRepos": ["*"],
"destinations": [{"server": "*", "namespace": "*"}]
}
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local proj = c.projects:get("default")
assert.eq(proj.metadata.name, "default")
assert.eq(proj.spec.description, "Default project")
assert.eq(proj.spec.sourceRepos[1], "*")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_repositories_list() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/repositories"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {},
"items": [
{
"repo": "https://github.com/argoproj/argocd-example-apps",
"type": "git",
"connectionState": {"status": "Successful"}
}
]
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local repos = c.repositories:list()
assert.eq(#repos, 1)
assert.eq(repos[1].type, "git")
assert.eq(repos[1].connectionState.status, "Successful")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_clusters_list() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/clusters"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {},
"items": [
{
"server": "https://kubernetes.default.svc",
"name": "in-cluster",
"connectionState": {"status": "Successful"},
"info": {"serverVersion": "1.28.0"}
}
]
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local clusters = c.clusters:list()
assert.eq(#clusters, 1)
assert.eq(clusters[1].name, "in-cluster")
assert.eq(clusters[1].connectionState.status, "Successful")
assert.eq(clusters[1].info.serverVersion, "1.28.0")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_settings() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/settings"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"url": "https://argocd.example.com",
"dexConfig": {"connectors": []},
"statusBadgeEnabled": true,
"kustomizeVersions": ["v5.0.0"]
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local settings = c.settings:get()
assert.eq(settings.url, "https://argocd.example.com")
assert.eq(settings.statusBadgeEnabled, true)
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_version() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/version"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"Version": "v2.10.0+abc123",
"BuildDate": "2024-01-15T00:00:00Z",
"GitCommit": "abc123def456",
"GitTreeState": "clean",
"GoVersion": "go1.21.5",
"Compiler": "gc",
"Platform": "linux/amd64"
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local v = c:version()
assert.eq(v.Version, "v2.10.0+abc123")
assert.eq(v.GitCommit, "abc123def456")
assert.eq(v.Platform, "linux/amd64")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_is_healthy_true() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/applications/guestbook"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {"name": "guestbook"},
"spec": {"project": "default"},
"status": {
"health": {"status": "Healthy"},
"sync": {"status": "Synced"}
}
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
assert.eq(c.apps:is_healthy("guestbook"), true)
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_is_healthy_false() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/applications/guestbook"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {"name": "guestbook"},
"spec": {"project": "default"},
"status": {
"health": {"status": "Degraded", "message": "Container failing"},
"sync": {"status": "Synced"}
}
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
assert.eq(c.apps:is_healthy("guestbook"), false)
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_is_synced_true() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/applications/guestbook"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {"name": "guestbook"},
"spec": {"project": "default"},
"status": {
"health": {"status": "Healthy"},
"sync": {"status": "Synced"}
}
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
assert.eq(c.apps:is_synced("guestbook"), true)
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_is_synced_false() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/applications/guestbook"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"metadata": {"name": "guestbook"},
"spec": {"project": "default"},
"status": {
"health": {"status": "Healthy"},
"sync": {"status": "OutOfSync"}
}
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
assert.eq(c.apps:is_synced("guestbook"), false)
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_error_on_failure() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/v1/applications/missing"))
.respond_with(
ResponseTemplate::new(404).set_body_string(r#"{"message":"application not found"}"#),
)
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}")
local ok, err = pcall(function() c.apps:get("missing") end)
assert.eq(ok, false)
assert.matches(err, "HTTP 404")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}
#[tokio::test]
async fn test_argocd_strip_trailing_slashes() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/api/version"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"Version": "v2.10.0"
})))
.mount(&server)
.await;
let script = format!(
r#"
local argocd = require("assay.argocd")
local c = argocd.client("{}///")
local v = c:version()
assert.eq(v.Version, "v2.10.0")
"#,
server.uri()
);
run_lua(&script).await.unwrap();
}