Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ These principles should guide all development decisions, code reviews, and featu

14. **When adding new templates**: Read [`docs/technical/template-system-architecture.md`](docs/technical/template-system-architecture.md) to understand the Project Generator pattern. The `templates/` directory contains source templates. Dynamic templates (`.tera`) are automatically processed, but static files must be explicitly registered in their respective `ProjectGenerator` to be copied to the build directory.

15. **When writing unit tests** (CRITICAL for test quality): Read [`docs/contributing/testing/unit-testing.md`](docs/contributing/testing/unit-testing.md) and follow the behavior-driven naming convention. **NEVER use the `test_` prefix** for test function names. Always use the `it_should_{expected_behavior}_when_{condition}` or `it_should_{expected_behavior}_given_{state}` pattern. This ensures tests clearly document the behavior being validated and the conditions under which it occurs. Example: `it_should_return_error_when_username_is_invalid()` instead of `test_invalid_username()`. Test names should follow the three-part structure (What-When-Then) and be descriptive enough that the test's purpose is clear without reading the code.

## 🧪 Build & Test

- **Setup Dependencies**: `cargo run --bin dependency-installer install` (sets up required development tools)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,22 @@ This refactoring systematically renames all unit test functions that use the `te

## 📊 Progress Tracking

**Total Active Proposals**: 21
**Total Active Proposals**: 0
**Total Postponed**: 0
**Total Discarded**: 0
**Completed**: 0
**Completed**: 16
**In Progress**: 0
**Not Started**: 21
**Not Started**: 0

### Phase Summary

- **Phase 0 - Core Application Layer (High Impact, Low Effort)**: ⏳ 0/6 completed (0%)
- **Phase 1 - Infrastructure Layer (High Impact, Low Effort)**: ⏳ 0/4 completed (0%)
- **Phase 2 - Presentation Layer (High Impact, Medium Effort)**: ⏳ 0/5 completed (0%)
- **Phase 3 - Testing Utilities (Medium Impact, Low Effort)**: ⏳ 0/4 completed (0%)
- **Phase 4 - Integration Tests (Medium Impact, Low Effort)**: ⏳ 0/2 completed (0%)
- **Phase 0 - Core Application Layer (High Impact, Low Effort)**: ✅ 6/6 completed (100%)
- **Phase 1 - Infrastructure Layer (High Impact, Low Effort)**: ✅ 4/4 completed (100%)
- **Phase 2 - Presentation Layer (High Impact, Medium Effort)**: ✅ 2/2 completed (100%)
- **Phase 3 - Testing Utilities (Medium Impact, Low Effort)**: ✅ 3/3 completed (100%)
- **Phase 4 - Integration Tests (Medium Impact, Low Effort)**: ✅ 1/1 completed (100%)

**Note**: Some proposals were consolidated during implementation. Proposals 10 (SSH connectivity methods - kept as-is), 12-15, 18-19, and 21 were not needed as those files had no test\_ prefix functions or were already correctly named.

### Discarded Proposals

Expand Down Expand Up @@ -836,5 +838,9 @@ Remember to run `./scripts/pre-commit.sh` before each commit. This ensures:

**Created**: December 12, 2025
**Last Updated**: December 12, 2025
**Status**: 📋 Planning
**Status**: ✅ Completed
**Issue**: [#227](https://github.com/torrust/torrust-tracker-deployer/issues/227)

## Summary

Successfully renamed 93 test functions and 14 helper functions across 20 files to follow the repository's behavior-driven naming conventions. All tests pass and all linters pass.
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ mod tests {
}

#[test]
fn test_create_environment_creation_config() {
fn it_should_create_environment_creation_config_when_provided_valid_inputs() {
let config = EnvironmentCreationConfig::new(
EnvironmentSection {
name: "dev".to_string(),
Expand All @@ -473,7 +473,7 @@ mod tests {
}

#[test]
fn test_deserialize_from_json_with_lxd_provider() {
fn it_should_deserialize_from_json_when_using_lxd_provider() {
let json = r#"{
"environment": {
"name": "e2e-config"
Expand Down Expand Up @@ -528,7 +528,7 @@ mod tests {
}

#[test]
fn test_deserialize_from_json_with_hetzner_provider() {
fn it_should_deserialize_from_json_when_using_hetzner_provider() {
let json = r#"{
"environment": {
"name": "production",
Expand Down Expand Up @@ -587,7 +587,7 @@ mod tests {
}

#[test]
fn test_serialize_environment_creation_config() {
fn it_should_serialize_to_json_when_converting_environment_creation_config() {
let config = EnvironmentCreationConfig::new(
EnvironmentSection {
name: "staging".to_string(),
Expand All @@ -610,7 +610,7 @@ mod tests {
}

#[test]
fn test_convert_to_environment_params_success_auto_generated_instance_name() {
fn it_should_convert_to_environment_params_when_using_auto_generated_instance_name() {
use std::env;

let project_root = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
Expand Down Expand Up @@ -640,7 +640,7 @@ mod tests {
}

#[test]
fn test_convert_to_environment_params_success_custom_instance_name() {
fn it_should_convert_to_environment_params_when_using_custom_instance_name() {
use std::env;

let project_root = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
Expand Down Expand Up @@ -668,7 +668,7 @@ mod tests {
}

#[test]
fn test_convert_to_environment_params_invalid_environment_name() {
fn it_should_return_error_when_environment_name_is_invalid() {
use std::env;

let project_root = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
Expand Down Expand Up @@ -697,7 +697,7 @@ mod tests {
}

#[test]
fn test_convert_to_environment_params_invalid_instance_name() {
fn it_should_return_error_when_instance_name_is_invalid() {
use std::env;

let project_root = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
Expand Down Expand Up @@ -727,7 +727,7 @@ mod tests {
}

#[test]
fn test_convert_to_environment_params_invalid_profile_name() {
fn it_should_return_error_when_profile_name_is_invalid() {
use std::env;

let project_root = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
Expand Down Expand Up @@ -758,7 +758,7 @@ mod tests {
}

#[test]
fn test_convert_to_environment_params_invalid_username() {
fn it_should_return_error_when_username_is_invalid() {
use std::env;

let project_root = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
Expand Down Expand Up @@ -792,7 +792,7 @@ mod tests {
}

#[test]
fn test_convert_to_environment_params_private_key_not_found() {
fn it_should_return_error_when_private_key_file_not_found() {
use std::env;

let project_root = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
Expand Down Expand Up @@ -825,7 +825,7 @@ mod tests {
}

#[test]
fn test_convert_to_environment_params_public_key_not_found() {
fn it_should_return_error_when_public_key_file_not_found() {
use std::env;

let project_root = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
Expand Down Expand Up @@ -858,7 +858,7 @@ mod tests {
}

#[test]
fn test_integration_with_environment_new() {
fn it_should_integrate_with_environment_new_when_creating_from_config() {
// This test verifies that the converted parameters work with Environment::new()
use crate::domain::Environment;
use std::env;
Expand Down Expand Up @@ -889,7 +889,7 @@ mod tests {
}

#[test]
fn test_round_trip_serialization() {
fn it_should_preserve_data_when_performing_round_trip_serialization() {
let original = EnvironmentCreationConfig::new(
EnvironmentSection {
name: "dev".to_string(),
Expand All @@ -912,7 +912,7 @@ mod tests {
}

#[test]
fn test_template_has_placeholder_values() {
fn it_should_contain_placeholder_values_when_generating_lxd_template() {
let template = EnvironmentCreationConfig::template(Provider::Lxd);

assert_eq!(template.environment.name, "REPLACE_WITH_ENVIRONMENT_NAME");
Expand All @@ -931,7 +931,7 @@ mod tests {
}

#[test]
fn test_template_for_hetzner_has_placeholder_values() {
fn it_should_contain_placeholder_values_when_generating_hetzner_template() {
let template = EnvironmentCreationConfig::template(Provider::Hetzner);

assert_eq!(template.environment.name, "REPLACE_WITH_ENVIRONMENT_NAME");
Expand Down Expand Up @@ -959,7 +959,7 @@ mod tests {
}

#[test]
fn test_template_serializes_to_valid_json() {
fn it_should_serialize_to_valid_json_when_converting_template() {
let template = EnvironmentCreationConfig::template(Provider::Lxd);
let json = serde_json::to_string_pretty(&template).unwrap();

Expand All @@ -974,7 +974,7 @@ mod tests {
}

#[test]
fn test_template_structure_matches_config() {
fn it_should_match_config_structure_when_validating_template() {
let template = EnvironmentCreationConfig::template(Provider::Lxd);

// Verify template has same structure as regular config
Expand Down Expand Up @@ -1011,7 +1011,7 @@ mod tests {
}

#[test]
fn test_generate_template_file() {
fn it_should_generate_template_file_when_creating_new_template() {
use tempfile::TempDir;

let temp_dir = TempDir::new().unwrap();
Expand Down Expand Up @@ -1039,7 +1039,7 @@ mod tests {
}

#[test]
fn test_generate_template_file_creates_parent_directories() {
fn it_should_create_parent_directories_when_generating_template_file() {
use tempfile::TempDir;

let temp_dir = TempDir::new().unwrap();
Expand All @@ -1058,7 +1058,7 @@ mod tests {
}

#[test]
fn test_generate_template_file_overwrites_existing() {
fn it_should_overwrite_existing_file_when_generating_template() {
use tempfile::TempDir;

let temp_dir = TempDir::new().unwrap();
Expand All @@ -1079,7 +1079,7 @@ mod tests {
}

#[test]
fn test_generate_template_file_sync() {
fn it_should_generate_template_file_synchronously_when_called() {
use tempfile::TempDir;

let temp_dir = TempDir::new().unwrap();
Expand All @@ -1105,7 +1105,7 @@ mod tests {
}

#[test]
fn test_generate_template_file_sync_creates_parent_directories() {
fn it_should_create_parent_directories_when_generating_template_file_sync() {
use tempfile::TempDir;

let temp_dir = TempDir::new().unwrap();
Expand Down
20 changes: 10 additions & 10 deletions src/application/command_handlers/create/config/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ mod tests {
use crate::shared::Username;

#[test]
fn test_invalid_environment_name_error() {
fn it_should_return_error_when_environment_name_is_invalid() {
let result = EnvironmentName::new("Invalid_Name");
assert!(result.is_err());

Expand All @@ -388,7 +388,7 @@ mod tests {
}

#[test]
fn test_invalid_username_error() {
fn it_should_return_error_when_username_is_invalid() {
let result = Username::new("123invalid");
assert!(result.is_err());

Expand All @@ -399,7 +399,7 @@ mod tests {
}

#[test]
fn test_private_key_not_found_error() {
fn it_should_return_error_when_private_key_file_not_found() {
let error = CreateConfigError::PrivateKeyNotFound {
path: PathBuf::from("/nonexistent/key"),
};
Expand All @@ -410,7 +410,7 @@ mod tests {
}

#[test]
fn test_public_key_not_found_error() {
fn it_should_return_error_when_public_key_file_not_found() {
let error = CreateConfigError::PublicKeyNotFound {
path: PathBuf::from("/nonexistent/key.pub"),
};
Expand All @@ -421,7 +421,7 @@ mod tests {
}

#[test]
fn test_invalid_port_error() {
fn it_should_return_error_when_port_is_invalid() {
let error = CreateConfigError::InvalidPort { port: 0 };
assert!(error.to_string().contains("Invalid SSH port"));
assert!(error.to_string().contains("must be between 1 and 65535"));
Expand All @@ -430,7 +430,7 @@ mod tests {
}

#[test]
fn test_all_errors_have_help() {
fn it_should_provide_help_messages_for_all_errors() {
// Verify all error variants have help text
let errors = vec![
CreateConfigError::PrivateKeyNotFound {
Expand All @@ -457,7 +457,7 @@ mod tests {
}

#[test]
fn test_invalid_instance_name_error() {
fn it_should_return_error_when_instance_name_is_invalid() {
let error = CreateConfigError::InvalidInstanceName {
name: "invalid-".to_string(),
reason: "Instance name must not end with a dash".to_string(),
Expand All @@ -471,7 +471,7 @@ mod tests {
}

#[test]
fn test_template_serialization_failed_error() {
fn it_should_return_error_when_template_serialization_fails() {
// Simulate serialization error (hard to create naturally)
let json_error = serde_json::from_str::<serde_json::Value>("invalid").unwrap_err();
let error = CreateConfigError::TemplateSerializationFailed { source: json_error };
Expand All @@ -484,7 +484,7 @@ mod tests {
}

#[test]
fn test_template_directory_creation_failed_error() {
fn it_should_return_error_when_template_directory_creation_fails() {
let error = CreateConfigError::TemplateDirectoryCreationFailed {
path: PathBuf::from("/test/path"),
source: std::io::Error::new(std::io::ErrorKind::PermissionDenied, "test"),
Expand All @@ -497,7 +497,7 @@ mod tests {
}

#[test]
fn test_template_file_write_failed_error() {
fn it_should_return_error_when_template_file_write_fails() {
let error = CreateConfigError::TemplateFileWriteFailed {
path: PathBuf::from("/test/file.json"),
source: std::io::Error::new(std::io::ErrorKind::PermissionDenied, "test"),
Expand Down
Loading
Loading