use client_core::container::{DockerManager, ServiceConfig};
use std::path::PathBuf;
use tempfile::tempdir;
const TEST_COMPOSE_CONTENT: &str = r#"
version: '3.8'
services:
frontend:
image: nginx:latest
ports:
- "80:80"
restart: always
backend:
image: node:16-alpine
ports:
- "3000:3000"
restart: unless-stopped
database:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
restart: on-failure
# 一次性服务 - 数据库初始化
db-init:
image: mysql:8.0
command: ["mysql", "-h", "database", "-u", "root", "-proot", "-e", "CREATE DATABASE IF NOT EXISTS test;"]
depends_on:
- database
restart: "no"
# 一次性服务 - 权限修复
permission-fix:
image: busybox:latest
command: ["sh", "-c", "chmod 755 /data"]
volumes:
- "./data:/data"
restart: "false"
# 没有restart配置的服务(默认不重启)
migration:
image: alpine:latest
command: ["echo", "running migration"]
networks:
default:
driver: bridge
"#;
const TEST_ENV_CONTENT: &str = r#"
# 测试环境变量
DOCKER_REGISTRY=localhost:5000
FRONTEND_VERSION=1.0.0
BACKEND_VERSION=1.0.0
DATABASE_VERSION=1.0.0
"#;
#[cfg(test)]
mod tests {
use super::*;
fn create_test_files() -> (tempfile::TempDir, PathBuf, PathBuf) {
let temp_dir = tempdir().expect("Failed to create temp dir");
let compose_path = temp_dir.path().join("docker-compose.yml");
let env_path = temp_dir.path().join(".env");
std::fs::write(&compose_path, TEST_COMPOSE_CONTENT).expect("Failed to write compose file");
std::fs::write(&env_path, TEST_ENV_CONTENT).expect("Failed to write env file");
(temp_dir, compose_path, env_path)
}
#[tokio::test]
async fn test_is_oneshot_service() {
let (_temp_dir, compose_path, env_path) = create_test_files();
let manager =
DockerManager::new(compose_path, env_path).expect("Failed to create DockerManager");
let result = manager.is_oneshot_service("permission-fix").await;
assert!(result.is_ok());
assert!(result.unwrap());
let result = manager.is_oneshot_service("frontend").await;
assert!(result.is_ok());
assert!(!result.unwrap());
let result = manager.is_oneshot_service("backend").await;
assert!(result.is_ok());
assert!(!result.unwrap());
let result = manager.is_oneshot_service("database").await;
assert!(result.is_ok());
assert!(!result.unwrap());
let result = manager.is_oneshot_service("non-existent").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_parse_service_config() {
let (_temp_dir, compose_path, env_path) = create_test_files();
let manager =
DockerManager::new(compose_path, env_path).expect("Failed to create DockerManager");
let result = manager.parse_service_config("frontend").await;
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.restart, Some("always".to_string()));
let result = manager.parse_service_config("backend").await;
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.restart, Some("unless-stopped".to_string()));
let result = manager.parse_service_config("database").await;
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.restart, Some("on-failure".to_string()));
let result = manager.parse_service_config("db-init").await;
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.restart, Some("no".to_string()));
let result = manager.parse_service_config("permission-fix").await;
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.restart, Some("false".to_string()));
let result = manager.parse_service_config("migration").await;
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.restart, None);
let result = manager.parse_service_config("non-existent").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_get_compose_service_names() {
let (_temp_dir, compose_path, env_path) = create_test_files();
let manager =
DockerManager::new(compose_path, env_path).expect("Failed to create DockerManager");
let result = manager.get_compose_service_names().await;
assert!(result.is_ok());
let service_names = result.unwrap();
assert_eq!(service_names.len(), 6);
let expected_services = vec![
"frontend",
"backend",
"database",
"db-init",
"permission-fix",
"migration",
];
for service in expected_services {
assert!(
service_names.contains(service),
"Service {service} not found"
);
}
}
#[tokio::test]
async fn test_with_fixtures_file() {
let compose_path = PathBuf::from("fixtures/docker-compose.yml");
let env_path = PathBuf::from("fixtures/.env");
if compose_path.exists() && env_path.exists() {
let manager =
DockerManager::new(compose_path, env_path).expect("Failed to create DockerManager");
let result = manager.get_compose_service_names().await;
assert!(result.is_ok());
let service_names = result.unwrap();
assert!(service_names.len() >= 10);
assert!(service_names.contains("frontend"));
assert!(service_names.contains("backend"));
assert!(service_names.contains("mysql"));
assert!(service_names.contains("mysql-permission-fix"));
assert!(service_names.contains("redis"));
let result = manager.is_oneshot_service("mysql-permission-fix").await;
assert!(result.is_ok());
assert!(result.unwrap());
let result = manager.is_oneshot_service("mysql").await;
assert!(result.is_ok());
assert!(!result.unwrap());
let result = manager.is_oneshot_service("frontend").await;
assert!(result.is_ok());
assert!(!result.unwrap());
let result = manager.parse_service_config("mysql").await;
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.restart, Some("always".to_string()));
let result = manager.parse_service_config("mysql-permission-fix").await;
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.restart, Some("no".to_string()));
} else {
println!("Fixtures files not found, skipping integration test");
}
}
#[tokio::test]
async fn test_service_config_struct() {
let config = ServiceConfig {
restart: Some("always".to_string()),
};
assert_eq!(config.restart, Some("always".to_string()));
let config = ServiceConfig { restart: None };
assert_eq!(config.restart, None);
}
}