use std::sync::Arc;
mod common;
use common::start_mock_server;
use kaji::client::KeycloakClient;
use kaji::models::RealmRepresentation;
use kaji::{apply, clean, inspect, plan};
use std::fs;
use tempfile::tempdir;
use kaji::utils::ui::MockUi;
#[tokio::test]
async fn test_plan_edge_cases() {
let mock_url = start_mock_server().await;
let mut client = KeycloakClient::new(mock_url);
client.set_target_realm("test-realm".to_string());
client
.login("admin-cli", Some("secret"), None, None)
.await
.expect("Login failed");
let dir = tempdir().unwrap();
let workspace_dir = dir.path().to_path_buf();
let resolver = Arc::new(kaji::utils::secrets::EnvResolver::new(
std::collections::HashMap::new(),
)) as Arc<dyn kaji::utils::secrets::SecretResolver>;
let ui = Arc::new(MockUi {
inputs: std::sync::Mutex::new(Vec::new()),
confirms: std::sync::Mutex::new(Vec::new()),
selects: std::sync::Mutex::new(Vec::new()),
passwords: std::sync::Mutex::new(Vec::new()),
});
let res = plan::run(
&client,
workspace_dir.join("non-existent"),
false,
false,
&[],
ui.clone(),
resolver.clone(),
None,
)
.await;
assert!(res.is_err());
let res = plan::run(
&client,
workspace_dir.clone(),
false,
false,
&[],
ui.clone(),
resolver.clone(),
None,
)
.await;
assert!(res.is_ok());
fs::write(workspace_dir.join(".secrets"), "TEST_VAR=test_value").unwrap();
let realm_dir = workspace_dir.join("new-realm");
fs::create_dir(&realm_dir).unwrap();
let realm = RealmRepresentation {
realm: "new-realm".to_string(),
enabled: Some(true),
display_name: Some("New Realm".to_string()),
extra: std::collections::HashMap::new(),
};
fs::write(
realm_dir.join("realm.yaml"),
serde_yaml::to_string(&realm).unwrap(),
)
.unwrap();
plan::run(
&client,
workspace_dir.clone(),
false,
false,
&[],
ui.clone(),
resolver.clone(),
None,
)
.await
.unwrap();
plan::run(
&client,
workspace_dir.clone(),
false,
false,
&["new-realm".to_string()],
ui.clone(),
resolver.clone(),
None,
)
.await
.unwrap();
fs::write(realm_dir.join("invalid.yaml"), "invalid: [yaml").unwrap();
let _res = plan::run(
&client,
workspace_dir.clone(),
false,
false,
&["new-realm".to_string()],
ui.clone(),
resolver.clone(),
None,
)
.await;
let roles_dir = realm_dir.join("roles");
fs::create_dir_all(&roles_dir).unwrap();
fs::write(roles_dir.join("invalid.yaml"), "invalid: [yaml").unwrap();
let res = plan::run(
&client,
workspace_dir.clone(),
false,
false,
&["new-realm".to_string()],
ui.clone(),
resolver,
None,
)
.await;
assert!(res.is_err());
}
#[tokio::test]
async fn test_apply_edge_cases() {
let mock_url = start_mock_server().await;
let mut client = KeycloakClient::new(mock_url);
client.set_target_realm("test-realm".to_string());
client
.login("admin-cli", Some("secret"), None, None)
.await
.expect("Login failed");
let dir = tempdir().unwrap();
let workspace_dir = dir.path().to_path_buf();
let resolver = Arc::new(kaji::utils::secrets::EnvResolver::new(
std::collections::HashMap::new(),
)) as Arc<dyn kaji::utils::secrets::SecretResolver>;
let ui = Arc::new(MockUi {
inputs: std::sync::Mutex::new(Vec::new()),
confirms: std::sync::Mutex::new(Vec::new()),
selects: std::sync::Mutex::new(Vec::new()),
passwords: std::sync::Mutex::new(Vec::new()),
});
let res = apply::run(
&client,
workspace_dir.join("non-existent"),
&[],
true,
false,
ui.clone(),
resolver.clone(),
None,
)
.await;
assert!(res.is_err());
let res = apply::run(
&client,
workspace_dir.clone(),
&[],
true,
false,
ui.clone(),
resolver.clone(),
None,
)
.await;
assert!(res.is_ok());
fs::write(workspace_dir.join(".secrets"), "TEST_VAR=test_value").unwrap();
let realm_dir = workspace_dir.join("test-realm");
fs::create_dir(&realm_dir).unwrap();
let realm = RealmRepresentation {
realm: "test-realm".to_string(),
enabled: Some(true),
display_name: Some("Test Realm".to_string()),
extra: std::collections::HashMap::new(),
};
fs::write(
realm_dir.join("realm.yaml"),
serde_yaml::to_string(&realm).unwrap(),
)
.unwrap();
apply::run(
&client,
workspace_dir.clone(),
&[],
true,
false,
ui.clone(),
resolver.clone(),
None,
)
.await
.unwrap();
fs::write(workspace_dir.join(".kajiplan"), "[]").unwrap();
apply::run(
&client,
workspace_dir.clone(),
&["test-realm".to_string()],
true,
false,
ui.clone(),
resolver.clone(),
None,
)
.await
.unwrap();
let roles_dir = realm_dir.join("roles");
fs::create_dir_all(&roles_dir).unwrap();
fs::write(roles_dir.join("invalid.yaml"), "invalid: [yaml").unwrap();
let res = apply::run(
&client,
workspace_dir.clone(),
&["test-realm".to_string()],
true,
false,
ui,
resolver,
None,
)
.await;
assert!(res.is_err());
}
#[tokio::test]
async fn test_check_keys_drift() {
let mock_url = start_mock_server().await;
let mut client = KeycloakClient::new(mock_url);
client.set_target_realm("test-realm".to_string());
let dir = tempdir().unwrap();
let workspace_dir = dir.path().to_path_buf();
let realm_dir = workspace_dir.join("test-realm");
fs::create_dir(&realm_dir).unwrap();
let resolver = Arc::new(kaji::utils::secrets::EnvResolver::new(
std::collections::HashMap::new(),
)) as Arc<dyn kaji::utils::secrets::SecretResolver>;
let ui = Arc::new(MockUi {
inputs: std::sync::Mutex::new(Vec::new()),
confirms: std::sync::Mutex::new(Vec::new()),
selects: std::sync::Mutex::new(Vec::new()),
passwords: std::sync::Mutex::new(Vec::new()),
});
plan::run(
&client,
workspace_dir,
true,
false,
&["test-realm".to_string()],
ui,
resolver,
None,
)
.await
.unwrap();
}
#[tokio::test]
async fn test_inspect_edge_cases() {
let mock_url = start_mock_server().await;
let mut client = KeycloakClient::new(mock_url);
client.set_target_realm("test-realm".to_string());
client
.login("admin-cli", Some("secret"), None, None)
.await
.expect("Login failed");
let dir = tempdir().unwrap();
let workspace_dir = dir.path().to_path_buf();
inspect::run(&client, workspace_dir.clone(), &[], true)
.await
.unwrap();
assert!(workspace_dir.join("test-realm").exists());
fs::write(workspace_dir.join(".secrets"), "OLD_VAR=old_value\n").unwrap();
inspect::run(
&client,
workspace_dir.clone(),
&["test-realm".to_string()],
true,
)
.await
.unwrap();
let secrets = fs::read_to_string(workspace_dir.join(".secrets")).unwrap();
assert!(secrets.contains("OLD_VAR=old_value"));
inspect::run(
&client,
workspace_dir.clone(),
&["test-realm".to_string()],
true,
)
.await
.unwrap();
let bad_client = KeycloakClient::new("http://invalid".to_string());
let res = inspect::run(
&bad_client,
workspace_dir.clone(),
&["test-realm".to_string()],
true,
)
.await;
assert!(res.is_err());
}
#[tokio::test]
async fn test_clean_edge_cases() {
let dir = tempdir().unwrap();
let workspace_dir = dir.path().to_path_buf();
let res = clean::run(workspace_dir.join("non-existent"), true, &[]).await;
assert!(res.is_ok());
let res = clean::run(workspace_dir.clone(), true, &["non-existent".to_string()]).await;
assert!(res.is_ok());
fs::create_dir_all(&workspace_dir).unwrap();
let file_path = workspace_dir.join("some_file.txt");
fs::write(&file_path, "test").unwrap();
clean::run(workspace_dir.clone(), true, &["some_file.txt".to_string()])
.await
.unwrap();
assert!(!file_path.exists());
}
#[tokio::test]
async fn test_validate_edge_cases() {
let dir = tempdir().unwrap();
let workspace_dir = dir.path().to_path_buf();
let res = kaji::validate::run(workspace_dir.join("non-existent"), &[]).await;
assert!(res.is_err());
fs::create_dir_all(&workspace_dir).unwrap();
let res = kaji::validate::run(workspace_dir.clone(), &[]).await;
assert!(res.is_ok());
let realm_dir = workspace_dir.join("test-realm");
fs::create_dir(&realm_dir).unwrap();
let realm = RealmRepresentation {
realm: "test-realm".to_string(),
enabled: Some(true),
display_name: Some("Test Realm".to_string()),
extra: std::collections::HashMap::new(),
};
fs::write(
realm_dir.join("realm.yaml"),
serde_yaml::to_string(&realm).unwrap(),
)
.unwrap();
kaji::validate::run(workspace_dir.clone(), &[])
.await
.unwrap();
}
#[tokio::test]
async fn test_inspect_edge_cases_2() {
let mock_url = start_mock_server().await;
let mut client = KeycloakClient::new(mock_url);
client.set_target_realm("test-realm".to_string());
client.set_token("mock".to_string());
let dir = tempdir().unwrap();
let workspace_dir = dir.path().to_path_buf();
let mut server = mockito::Server::new_async().await;
let mut bad_client = KeycloakClient::new(server.url());
bad_client.set_token("mock".to_string());
let _m = server
.mock("GET", "/admin/realms")
.with_status(500)
.create_async()
.await;
let res = inspect::run(&bad_client, workspace_dir.clone(), &[], true).await;
assert!(res.is_err());
}