diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2025-11-21 05:18:15 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2025-11-21 05:34:56 +0000 |
| commit | 7a81643367515a9d01eb2d4deb623e9a7c071a12 (patch) | |
| tree | 88d6f2e69ca051d2c94269f4753e2ef807882438 /tests | |
| parent | 7dda553918705277c7fa5b903c6a40e4b4a0aa8d (diff) | |
add repository creation
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/common/relay.rs | 37 | ||||
| -rw-r--r-- | tests/repository_creation.rs | 64 |
2 files changed, 99 insertions, 2 deletions
diff --git a/tests/common/relay.rs b/tests/common/relay.rs index 7185acd..6b512cd 100644 --- a/tests/common/relay.rs +++ b/tests/common/relay.rs | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | //! | 2 | //! |
| 3 | //! Provides automatic relay lifecycle management for integration tests. | 3 | //! Provides automatic relay lifecycle management for integration tests. |
| 4 | 4 | ||
| 5 | use nostr_sdk::ToBech32; | ||
| 6 | use std::path::PathBuf; | ||
| 5 | use std::process::{Child, Command, Stdio}; | 7 | use std::process::{Child, Command, Stdio}; |
| 6 | use std::time::Duration; | 8 | use std::time::Duration; |
| 7 | use tokio::time::sleep; | 9 | use tokio::time::sleep; |
| @@ -9,11 +11,12 @@ use tokio::time::sleep; | |||
| 9 | /// Test relay fixture that manages relay lifecycle | 11 | /// Test relay fixture that manages relay lifecycle |
| 10 | /// | 12 | /// |
| 11 | /// Automatically starts and stops the ngit-grasp relay for testing. | 13 | /// Automatically starts and stops the ngit-grasp relay for testing. |
| 12 | /// Uses a random port to avoid conflicts. | 14 | /// Uses a random port to avoid conflicts and cleans up created repositories. |
| 13 | pub struct TestRelay { | 15 | pub struct TestRelay { |
| 14 | process: Child, | 16 | process: Child, |
| 15 | url: String, | 17 | url: String, |
| 16 | port: u16, | 18 | port: u16, |
| 19 | git_data_dir: tempfile::TempDir, | ||
| 17 | } | 20 | } |
| 18 | 21 | ||
| 19 | impl TestRelay { | 22 | impl TestRelay { |
| @@ -40,6 +43,10 @@ impl TestRelay { | |||
| 40 | let bind_address = format!("127.0.0.1:{}", port); | 43 | let bind_address = format!("127.0.0.1:{}", port); |
| 41 | let url = format!("ws://127.0.0.1:{}", port); | 44 | let url = format!("ws://127.0.0.1:{}", port); |
| 42 | 45 | ||
| 46 | // Create temporary directory for git repositories | ||
| 47 | let git_data_dir = tempfile::tempdir() | ||
| 48 | .expect("Failed to create temporary git data directory"); | ||
| 49 | |||
| 43 | // Use the built binary directly (faster than cargo run) | 50 | // Use the built binary directly (faster than cargo run) |
| 44 | let binary_path = std::env::current_exe() | 51 | let binary_path = std::env::current_exe() |
| 45 | .expect("Failed to get current exe") | 52 | .expect("Failed to get current exe") |
| @@ -49,17 +56,29 @@ impl TestRelay { | |||
| 49 | .expect("Failed to get grandparent dir") | 56 | .expect("Failed to get grandparent dir") |
| 50 | .join("ngit-grasp"); | 57 | .join("ngit-grasp"); |
| 51 | 58 | ||
| 59 | // Generate a test owner npub (using a random keypair) | ||
| 60 | let test_keys = nostr_sdk::Keys::generate(); | ||
| 61 | let test_npub = test_keys.public_key().to_bech32() | ||
| 62 | .expect("Failed to generate test npub"); | ||
| 63 | |||
| 52 | // Start the relay process | 64 | // Start the relay process |
| 53 | let process = Command::new(&binary_path) | 65 | let process = Command::new(&binary_path) |
| 54 | .env("NGIT_BIND_ADDRESS", &bind_address) | 66 | .env("NGIT_BIND_ADDRESS", &bind_address) |
| 55 | .env("NGIT_DOMAIN", &bind_address) // Set domain to match bind address | 67 | .env("NGIT_DOMAIN", &bind_address) // Set domain to match bind address |
| 68 | .env("NGIT_GIT_DATA_PATH", git_data_dir.path()) | ||
| 69 | .env("NGIT_OWNER_NPUB", &test_npub) | ||
| 56 | .env("RUST_LOG", "warn") // Less logging during tests | 70 | .env("RUST_LOG", "warn") // Less logging during tests |
| 57 | .stdout(Stdio::null()) | 71 | .stdout(Stdio::null()) |
| 58 | .stderr(Stdio::null()) | 72 | .stderr(Stdio::null()) |
| 59 | .spawn() | 73 | .spawn() |
| 60 | .expect("Failed to start relay process"); | 74 | .expect("Failed to start relay process"); |
| 61 | 75 | ||
| 62 | let relay = Self { process, url, port }; | 76 | let relay = Self { |
| 77 | process, | ||
| 78 | url, | ||
| 79 | port, | ||
| 80 | git_data_dir, | ||
| 81 | }; | ||
| 63 | 82 | ||
| 64 | // Wait for relay to be ready | 83 | // Wait for relay to be ready |
| 65 | relay.wait_for_ready().await; | 84 | relay.wait_for_ready().await; |
| @@ -82,6 +101,20 @@ impl TestRelay { | |||
| 82 | format!("127.0.0.1:{}", self.port) | 101 | format!("127.0.0.1:{}", self.port) |
| 83 | } | 102 | } |
| 84 | 103 | ||
| 104 | /// Get the git data directory path | ||
| 105 | pub fn git_data_dir(&self) -> &std::path::Path { | ||
| 106 | self.git_data_dir.path() | ||
| 107 | } | ||
| 108 | |||
| 109 | /// Get the expected repository path for a given npub and repo identifier | ||
| 110 | /// | ||
| 111 | /// Repositories are stored at: <git_data_dir>/<npub>/<identifier>.git | ||
| 112 | pub fn repo_path(&self, npub: &str, identifier: &str) -> PathBuf { | ||
| 113 | self.git_data_dir.path() | ||
| 114 | .join(npub) | ||
| 115 | .join(format!("{}.git", identifier)) | ||
| 116 | } | ||
| 117 | |||
| 85 | /// Wait for the relay to be ready to accept connections | 118 | /// Wait for the relay to be ready to accept connections |
| 86 | async fn wait_for_ready(&self) { | 119 | async fn wait_for_ready(&self) { |
| 87 | let max_attempts = 50; // 5 seconds total | 120 | let max_attempts = 50; // 5 seconds total |
diff --git a/tests/repository_creation.rs b/tests/repository_creation.rs new file mode 100644 index 0000000..f57899d --- /dev/null +++ b/tests/repository_creation.rs | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | //! Repository Creation Integration Tests | ||
| 2 | //! | ||
| 3 | //! Tests that verify bare Git repositories are created when repository announcements | ||
| 4 | //! are accepted by ngit-grasp relay. | ||
| 5 | //! | ||
| 6 | //! # Test Strategy | ||
| 7 | //! | ||
| 8 | //! - Each test runs in complete isolation with its own fresh relay instance | ||
| 9 | //! - Uses macro to eliminate boilerplate while maintaining test isolation | ||
| 10 | //! - Calls individual test methods from grasp-audit for minimal duplication | ||
| 11 | //! - Automatic cleanup via TestRelay fixture (removes container and temp dirs) | ||
| 12 | //! | ||
| 13 | //! # Running Tests | ||
| 14 | //! | ||
| 15 | //! ```bash | ||
| 16 | //! # Run all repository creation tests | ||
| 17 | //! cargo test --test repository_creation | ||
| 18 | //! | ||
| 19 | //! # Run specific test | ||
| 20 | //! cargo test --test repository_creation test_bare_repo_created_on_announcement | ||
| 21 | //! | ||
| 22 | //! # With output | ||
| 23 | //! cargo test --test repository_creation -- --nocapture | ||
| 24 | //! ``` | ||
| 25 | |||
| 26 | mod common; | ||
| 27 | |||
| 28 | use common::TestRelay; | ||
| 29 | use grasp_audit::*; | ||
| 30 | use grasp_audit::specs::grasp01::RepositoryCreationTests; | ||
| 31 | |||
| 32 | /// Macro to generate isolated integration tests | ||
| 33 | /// | ||
| 34 | /// Each test runs with its own fresh relay instance to ensure complete isolation. | ||
| 35 | /// This eliminates issues with leftover repositories and ensures clean state. | ||
| 36 | macro_rules! isolated_test { | ||
| 37 | ($test_name:ident) => { | ||
| 38 | #[tokio::test] | ||
| 39 | async fn $test_name() { | ||
| 40 | let relay = TestRelay::start().await; | ||
| 41 | let config = AuditConfig::ci(); | ||
| 42 | let client = AuditClient::new(relay.url(), config) | ||
| 43 | .await | ||
| 44 | .expect("Failed to create audit client"); | ||
| 45 | |||
| 46 | let result = RepositoryCreationTests::$test_name(&client, relay.git_data_dir()).await; | ||
| 47 | |||
| 48 | relay.stop().await; | ||
| 49 | |||
| 50 | assert!( | ||
| 51 | result.passed, | ||
| 52 | "{} failed: {}", | ||
| 53 | stringify!($test_name), | ||
| 54 | result.error.as_deref().unwrap_or("unknown error") | ||
| 55 | ); | ||
| 56 | } | ||
| 57 | }; | ||
| 58 | } | ||
| 59 | |||
| 60 | // Generate isolated tests for all repository creation tests | ||
| 61 | isolated_test!(test_bare_repo_created_on_announcement); | ||
| 62 | isolated_test!(test_repo_creation_idempotent); | ||
| 63 | isolated_test!(test_bare_repo_structure); | ||
| 64 | isolated_test!(test_repo_cleanup); \ No newline at end of file | ||