405 lines
No EOL
15 KiB
Rust
405 lines
No EOL
15 KiB
Rust
/*
|
|
* This file is part of Sharenet.
|
|
*
|
|
* Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
|
|
*
|
|
* You may obtain a copy of the license at:
|
|
* https://creativecommons.org/licenses/by-nc-sa/4.0/
|
|
*
|
|
* Copyright (c) 2024 Continuist <continuist02@gmail.com>
|
|
*/
|
|
|
|
use anyhow::Result;
|
|
use clap::Parser;
|
|
use cli::Cli;
|
|
use application::Service;
|
|
use memory::{InMemoryUserRepository, InMemoryProductRepository};
|
|
use postgres::{PostgresUserRepository, PostgresProductRepository};
|
|
use uuid::Uuid;
|
|
use serial_test::serial;
|
|
use application::UseCase;
|
|
|
|
// Import the centralized test setup
|
|
use crate::test_setup::{setup_test_db, unique_test_data};
|
|
|
|
// Helper functions are now imported from test_setup module above
|
|
|
|
// Test CLI with memory repository
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_cli_with_memory_user_lifecycle() -> Result<()> {
|
|
let user_repo = InMemoryUserRepository::new();
|
|
let product_repo = InMemoryProductRepository::new();
|
|
let user_service = Service::new(user_repo);
|
|
let product_service = Service::new(product_repo);
|
|
|
|
// Test user create
|
|
let (username, email) = unique_test_data("test_user");
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "user", "create", "--username", &username, "--email", &email
|
|
]);
|
|
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test user list
|
|
let cli = Cli::parse_from(&["cli", "user", "list"]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test user get (we need to get the ID from the list first)
|
|
let users = user_service.list().await?;
|
|
assert!(!users.is_empty());
|
|
let user_id = users[0].id().to_string();
|
|
|
|
let cli = Cli::parse_from(&["cli", "user", "get", "--id", &user_id]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test user update
|
|
let new_username = format!("{}_updated", username);
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "user", "update", "--id", &user_id, "--username", &new_username
|
|
]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test user delete
|
|
let cli = Cli::parse_from(&["cli", "user", "delete", "--id", &user_id]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_cli_with_memory_product_lifecycle() -> Result<()> {
|
|
let user_repo = InMemoryUserRepository::new();
|
|
let product_repo = InMemoryProductRepository::new();
|
|
let user_service = Service::new(user_repo);
|
|
let product_service = Service::new(product_repo);
|
|
|
|
// Test product create
|
|
let (name, description) = unique_test_data("test_product");
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "product", "create", "--name", &name, "--description", &description
|
|
]);
|
|
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test product list
|
|
let cli = Cli::parse_from(&["cli", "product", "list"]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test product get (we need to get the ID from the list first)
|
|
let products = product_service.list().await?;
|
|
assert!(!products.is_empty());
|
|
let product_id = products[0].id().to_string();
|
|
|
|
let cli = Cli::parse_from(&["cli", "product", "get", "--id", &product_id]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test product update
|
|
let new_name = format!("{}_updated", name);
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "product", "update", "--id", &product_id, "--name", &new_name
|
|
]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test product delete
|
|
let cli = Cli::parse_from(&["cli", "product", "delete", "--id", &product_id]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_cli_with_memory_mixed_operations() -> Result<()> {
|
|
let user_repo = InMemoryUserRepository::new();
|
|
let product_repo = InMemoryProductRepository::new();
|
|
let user_service = Service::new(user_repo);
|
|
let product_service = Service::new(product_repo);
|
|
|
|
// Create multiple users and products
|
|
for i in 1..=3 {
|
|
let (username, email) = unique_test_data(&format!("user_{}", i));
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "user", "create", "--username", &username, "--email", &email
|
|
]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
let (name, description) = unique_test_data(&format!("product_{}", i));
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "product", "create", "--name", &name, "--description", &description
|
|
]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
}
|
|
|
|
// List all users and products
|
|
let cli = Cli::parse_from(&["cli", "user", "list"]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
let cli = Cli::parse_from(&["cli", "product", "list"]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Verify counts
|
|
let users = user_service.list().await?;
|
|
let products = product_service.list().await?;
|
|
assert_eq!(users.len(), 3);
|
|
assert_eq!(products.len(), 3);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// Test CLI with PostgreSQL repository
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_cli_with_postgres_user_lifecycle() -> Result<()> {
|
|
let pool = setup_test_db().await;
|
|
let user_repo = PostgresUserRepository::new(pool.clone());
|
|
let product_repo = PostgresProductRepository::new(pool.clone());
|
|
let user_service = Service::new(user_repo);
|
|
let product_service = Service::new(product_repo);
|
|
|
|
// Test user create
|
|
let (username, email) = unique_test_data("test_user");
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "user", "create", "--username", &username, "--email", &email
|
|
]);
|
|
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test user list
|
|
let cli = Cli::parse_from(&["cli", "user", "list"]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test user get (we need to get the ID from the list first)
|
|
let users = user_service.list().await?;
|
|
assert!(!users.is_empty());
|
|
let user_id = users[0].id().to_string();
|
|
|
|
let cli = Cli::parse_from(&["cli", "user", "get", "--id", &user_id]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test user update
|
|
let new_username = format!("{}_updated", username);
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "user", "update", "--id", &user_id, "--username", &new_username
|
|
]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test user delete
|
|
let cli = Cli::parse_from(&["cli", "user", "delete", "--id", &user_id]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_cli_with_postgres_product_lifecycle() -> Result<()> {
|
|
let pool = setup_test_db().await;
|
|
let user_repo = PostgresUserRepository::new(pool.clone());
|
|
let product_repo = PostgresProductRepository::new(pool.clone());
|
|
let user_service = Service::new(user_repo);
|
|
let product_service = Service::new(product_repo);
|
|
|
|
// Test product create
|
|
let (name, description) = unique_test_data("test_product");
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "product", "create", "--name", &name, "--description", &description
|
|
]);
|
|
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test product list
|
|
let cli = Cli::parse_from(&["cli", "product", "list"]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test product get (we need to get the ID from the list first)
|
|
let products = product_service.list().await?;
|
|
assert!(!products.is_empty());
|
|
let product_id = products[0].id().to_string();
|
|
|
|
let cli = Cli::parse_from(&["cli", "product", "get", "--id", &product_id]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test product update
|
|
let new_name = format!("{}_updated", name);
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "product", "update", "--id", &product_id, "--name", &new_name
|
|
]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Test product delete
|
|
let cli = Cli::parse_from(&["cli", "product", "delete", "--id", &product_id]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_cli_with_postgres_mixed_operations() -> Result<()> {
|
|
let pool = setup_test_db().await;
|
|
let user_repo = PostgresUserRepository::new(pool.clone());
|
|
let product_repo = PostgresProductRepository::new(pool.clone());
|
|
let user_service = Service::new(user_repo);
|
|
let product_service = Service::new(product_repo);
|
|
|
|
// Create multiple users and products
|
|
for i in 1..=3 {
|
|
let (username, email) = unique_test_data(&format!("user_{}", i));
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "user", "create", "--username", &username, "--email", &email
|
|
]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
let (name, description) = unique_test_data(&format!("product_{}", i));
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "product", "create", "--name", &name, "--description", &description
|
|
]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
}
|
|
|
|
// List all users and products
|
|
let cli = Cli::parse_from(&["cli", "user", "list"]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
let cli = Cli::parse_from(&["cli", "product", "list"]);
|
|
cli.run(user_service.clone(), product_service.clone()).await?;
|
|
|
|
// Verify counts
|
|
let users = user_service.list().await?;
|
|
let products = product_service.list().await?;
|
|
assert_eq!(users.len(), 3);
|
|
assert_eq!(products.len(), 3);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// Test error handling
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_cli_error_handling() -> Result<()> {
|
|
let user_repo = InMemoryUserRepository::new();
|
|
let product_repo = InMemoryProductRepository::new();
|
|
let user_service = Service::new(user_repo);
|
|
let product_service = Service::new(product_repo);
|
|
|
|
// Test getting non-existent user
|
|
let non_existent_id = Uuid::new_v4();
|
|
let cli = Cli::parse_from(&["cli", "user", "get", "--id", &non_existent_id.to_string()]);
|
|
let result = cli.run(user_service.clone(), product_service.clone()).await;
|
|
assert!(result.is_err());
|
|
|
|
// Test getting non-existent product
|
|
let cli = Cli::parse_from(&["cli", "product", "get", "--id", &non_existent_id.to_string()]);
|
|
let result = cli.run(user_service.clone(), product_service.clone()).await;
|
|
assert!(result.is_err());
|
|
|
|
// Test updating non-existent user
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "user", "update", "--id", &non_existent_id.to_string(), "--username", "new_name"
|
|
]);
|
|
let result = cli.run(user_service.clone(), product_service.clone()).await;
|
|
assert!(result.is_err());
|
|
|
|
// Test deleting non-existent user
|
|
let cli = Cli::parse_from(&["cli", "user", "delete", "--id", &non_existent_id.to_string()]);
|
|
let result = cli.run(user_service.clone(), product_service.clone()).await;
|
|
assert!(result.is_err());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// Test edge cases
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_cli_edge_cases() -> Result<()> {
|
|
let user_repo = InMemoryUserRepository::new();
|
|
let product_repo = InMemoryProductRepository::new();
|
|
let user_service = Service::new(user_repo);
|
|
let product_service = Service::new(product_repo);
|
|
|
|
// Test empty username (should fail validation)
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "user", "create", "--username", "", "--email", "test@example.com"
|
|
]);
|
|
let result = cli.run(user_service.clone(), product_service.clone()).await;
|
|
assert!(result.is_err());
|
|
|
|
// Test whitespace username (should fail validation)
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "user", "create", "--username", " ", "--email", "test@example.com"
|
|
]);
|
|
let result = cli.run(user_service.clone(), product_service.clone()).await;
|
|
assert!(result.is_err());
|
|
|
|
// Test empty email (should be allowed)
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "user", "create", "--username", "testuser", "--email", ""
|
|
]);
|
|
let result = cli.run(user_service.clone(), product_service.clone()).await;
|
|
assert!(result.is_ok());
|
|
|
|
// Test empty product name (should fail validation)
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "product", "create", "--name", "", "--description", ""
|
|
]);
|
|
let result = cli.run(user_service.clone(), product_service.clone()).await;
|
|
assert!(result.is_err());
|
|
|
|
// Test whitespace product name (should fail validation)
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "product", "create", "--name", " ", "--description", "desc"
|
|
]);
|
|
let result = cli.run(user_service.clone(), product_service.clone()).await;
|
|
assert!(result.is_err());
|
|
|
|
// Test empty product description (should be allowed)
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "product", "create", "--name", "Test Product", "--description", ""
|
|
]);
|
|
let result = cli.run(user_service.clone(), product_service.clone()).await;
|
|
assert!(result.is_ok());
|
|
|
|
// Test very long strings
|
|
let long_string = "a".repeat(1000);
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "user", "create", "--username", &long_string, "--email", "test@example.com"
|
|
]);
|
|
let _result = cli.run(user_service.clone(), product_service.clone()).await;
|
|
// Note: Very long strings are currently allowed by the domain layer
|
|
// This test documents the current behavior
|
|
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "product", "create", "--name", &long_string, "--description", "test"
|
|
]);
|
|
let _result = cli.run(user_service.clone(), product_service.clone()).await;
|
|
// Note: Very long strings are currently allowed by the domain layer
|
|
// This test documents the current behavior
|
|
|
|
// Test special characters
|
|
let special_chars = "!@#$%^&*()_+-=[]{}|;':\",./<>?";
|
|
let cli = Cli::parse_from(&[
|
|
"cli", "user", "create", "--username", special_chars, "--email", "test@example.com"
|
|
]);
|
|
let _result = cli.run(user_service.clone(), product_service.clone()).await;
|
|
// Note: Special characters are currently allowed by the domain layer
|
|
// This test documents the current behavior
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// Test no command provided
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_cli_no_command() -> Result<()> {
|
|
let user_repo = InMemoryUserRepository::new();
|
|
let product_repo = InMemoryProductRepository::new();
|
|
let user_service = Service::new(user_repo);
|
|
let product_service = Service::new(product_repo);
|
|
|
|
let cli = Cli::parse_from(&["cli"]);
|
|
cli.run(user_service, product_service).await?;
|
|
|
|
Ok(())
|
|
}
|