diff options
| -rw-r--r-- | tests/common/git_server.rs | 105 | ||||
| -rw-r--r-- | tests/common/mock_relay.rs | 43 |
2 files changed, 67 insertions, 81 deletions
diff --git a/tests/common/git_server.rs b/tests/common/git_server.rs index 6121adc..adf66b5 100644 --- a/tests/common/git_server.rs +++ b/tests/common/git_server.rs | |||
| @@ -390,10 +390,11 @@ mod tests { | |||
| 390 | // Start server | 390 | // Start server |
| 391 | let server = SimpleGitServer::start(temp_dir.path()).await; | 391 | let server = SimpleGitServer::start(temp_dir.path()).await; |
| 392 | 392 | ||
| 393 | // Run git ls-remote against the server | 393 | // Run git ls-remote against the server (using tokio::process::Command) |
| 394 | let output = Command::new("git") | 394 | let output = tokio::process::Command::new("git") |
| 395 | .args(["ls-remote", server.url()]) | 395 | .args(["ls-remote", server.url()]) |
| 396 | .output() | 396 | .output() |
| 397 | .await | ||
| 397 | .expect("Failed to run git ls-remote"); | 398 | .expect("Failed to run git ls-remote"); |
| 398 | 399 | ||
| 399 | assert!( | 400 | assert!( |
| @@ -433,27 +434,30 @@ mod tests { | |||
| 433 | // Create a destination repo to fetch into | 434 | // Create a destination repo to fetch into |
| 434 | let dest_dir = tempfile::tempdir().expect("Failed to create dest dir"); | 435 | let dest_dir = tempfile::tempdir().expect("Failed to create dest dir"); |
| 435 | 436 | ||
| 436 | // Initialize empty repo | 437 | // Initialize empty repo (using tokio::process::Command) |
| 437 | let output = Command::new("git") | 438 | let output = tokio::process::Command::new("git") |
| 438 | .args(["init"]) | 439 | .args(["init"]) |
| 439 | .current_dir(dest_dir.path()) | 440 | .current_dir(dest_dir.path()) |
| 440 | .output() | 441 | .output() |
| 442 | .await | ||
| 441 | .expect("Failed to init dest repo"); | 443 | .expect("Failed to init dest repo"); |
| 442 | assert!(output.status.success()); | 444 | assert!(output.status.success()); |
| 443 | 445 | ||
| 444 | // Add the server as a remote | 446 | // Add the server as a remote |
| 445 | let output = Command::new("git") | 447 | let output = tokio::process::Command::new("git") |
| 446 | .args(["remote", "add", "origin", server.url()]) | 448 | .args(["remote", "add", "origin", server.url()]) |
| 447 | .current_dir(dest_dir.path()) | 449 | .current_dir(dest_dir.path()) |
| 448 | .output() | 450 | .output() |
| 451 | .await | ||
| 449 | .expect("Failed to add remote"); | 452 | .expect("Failed to add remote"); |
| 450 | assert!(output.status.success()); | 453 | assert!(output.status.success()); |
| 451 | 454 | ||
| 452 | // Fetch from the server | 455 | // Fetch from the server |
| 453 | let output = Command::new("git") | 456 | let output = tokio::process::Command::new("git") |
| 454 | .args(["fetch", "origin"]) | 457 | .args(["fetch", "origin"]) |
| 455 | .current_dir(dest_dir.path()) | 458 | .current_dir(dest_dir.path()) |
| 456 | .output() | 459 | .output() |
| 460 | .await | ||
| 457 | .expect("Failed to fetch"); | 461 | .expect("Failed to fetch"); |
| 458 | 462 | ||
| 459 | assert!( | 463 | assert!( |
| @@ -463,10 +467,11 @@ mod tests { | |||
| 463 | ); | 467 | ); |
| 464 | 468 | ||
| 465 | // Verify the commit was fetched | 469 | // Verify the commit was fetched |
| 466 | let output = Command::new("git") | 470 | let output = tokio::process::Command::new("git") |
| 467 | .args(["rev-parse", "origin/main"]) | 471 | .args(["rev-parse", "origin/main"]) |
| 468 | .current_dir(dest_dir.path()) | 472 | .current_dir(dest_dir.path()) |
| 469 | .output() | 473 | .output() |
| 474 | .await | ||
| 470 | .expect("Failed to rev-parse"); | 475 | .expect("Failed to rev-parse"); |
| 471 | 476 | ||
| 472 | assert!(output.status.success()); | 477 | assert!(output.status.success()); |
| @@ -538,12 +543,10 @@ impl SmartGitServer { | |||
| 538 | /// # Panics | 543 | /// # Panics |
| 539 | /// Panics if the git operations fail or the server cannot start | 544 | /// Panics if the git operations fail or the server cannot start |
| 540 | pub async fn start(source_repo: &Path) -> Self { | 545 | pub async fn start(source_repo: &Path) -> Self { |
| 541 | println!("[SmartGitServer::start] Creating temp dir"); | ||
| 542 | // 1. Create temp directory for bare repo | 546 | // 1. Create temp directory for bare repo |
| 543 | let temp_dir = tempfile::tempdir().expect("Failed to create temp dir for git server"); | 547 | let temp_dir = tempfile::tempdir().expect("Failed to create temp dir for git server"); |
| 544 | let bare_repo_path = temp_dir.path().join("repo.git"); | 548 | let bare_repo_path = temp_dir.path().join("repo.git"); |
| 545 | 549 | ||
| 546 | println!("[SmartGitServer::start] Cloning bare repo from {:?}", source_repo); | ||
| 547 | // 2. Create bare clone | 550 | // 2. Create bare clone |
| 548 | let output = Command::new("git") | 551 | let output = Command::new("git") |
| 549 | .args(["clone", "--bare"]) | 552 | .args(["clone", "--bare"]) |
| @@ -558,44 +561,41 @@ impl SmartGitServer { | |||
| 558 | String::from_utf8_lossy(&output.stderr) | 561 | String::from_utf8_lossy(&output.stderr) |
| 559 | ); | 562 | ); |
| 560 | } | 563 | } |
| 561 | println!("[SmartGitServer::start] Bare clone created"); | ||
| 562 | 564 | ||
| 563 | // 3. Find a free port | 565 | // 3. Create and bind listener (eliminates port race condition) |
| 564 | println!("[SmartGitServer::start] Finding free port"); | 566 | let std_listener = std::net::TcpListener::bind("127.0.0.1:0") |
| 565 | let port = find_free_port(); | 567 | .expect("Failed to bind to random port"); |
| 566 | println!("[SmartGitServer::start] Found port {}", port); | 568 | let port = std_listener.local_addr() |
| 567 | let addr: SocketAddr = ([127, 0, 0, 1], port).into(); | 569 | .expect("Failed to get local addr") |
| 570 | .port(); | ||
| 571 | |||
| 572 | // Convert to tokio listener (keeps port bound) | ||
| 573 | std_listener.set_nonblocking(true) | ||
| 574 | .expect("Failed to set non-blocking"); | ||
| 575 | let listener = TcpListener::from_std(std_listener) | ||
| 576 | .expect("Failed to convert to tokio listener"); | ||
| 568 | 577 | ||
| 569 | // 4. Create shutdown channel | 578 | // 4. Create shutdown channel |
| 570 | let (shutdown_tx, mut shutdown_rx) = oneshot::channel::<()>(); | 579 | let (shutdown_tx, mut shutdown_rx) = oneshot::channel::<()>(); |
| 571 | 580 | ||
| 572 | println!("[SmartGitServer::start] Binding to {}", addr); | ||
| 573 | // 5. Start the HTTP server | 581 | // 5. Start the HTTP server |
| 574 | let repo_path = Arc::new(bare_repo_path); | 582 | let repo_path = Arc::new(bare_repo_path); |
| 575 | let listener = TcpListener::bind(addr) | ||
| 576 | .await | ||
| 577 | .expect("Failed to bind to address"); | ||
| 578 | println!("[SmartGitServer::start] Listener bound successfully"); | ||
| 579 | 583 | ||
| 580 | let handle = tokio::spawn(async move { | 584 | let handle = tokio::spawn(async move { |
| 581 | eprintln!("[SmartGitServer] Server loop started, waiting for connections..."); | ||
| 582 | loop { | 585 | loop { |
| 583 | tokio::select! { | 586 | tokio::select! { |
| 584 | accept_result = listener.accept() => { | 587 | accept_result = listener.accept() => { |
| 585 | match accept_result { | 588 | match accept_result { |
| 586 | Ok((stream, addr)) => { | 589 | Ok((stream, _addr)) => { |
| 587 | eprintln!("[SmartGitServer] Accepted connection from {}", addr); | ||
| 588 | let repo_path = Arc::clone(&repo_path); | 590 | let repo_path = Arc::clone(&repo_path); |
| 589 | let io = TokioIo::new(stream); | 591 | let io = TokioIo::new(stream); |
| 590 | 592 | ||
| 591 | tokio::spawn(async move { | 593 | tokio::spawn(async move { |
| 592 | eprintln!("[SmartGitServer] Spawning handler for connection"); | ||
| 593 | let service = service_fn(move |req| { | 594 | let service = service_fn(move |req| { |
| 594 | let repo_path = Arc::clone(&repo_path); | 595 | let repo_path = Arc::clone(&repo_path); |
| 595 | async move { handle_smart_request(req, &repo_path).await } | 596 | async move { handle_smart_request(req, &repo_path).await } |
| 596 | }); | 597 | }); |
| 597 | 598 | ||
| 598 | eprintln!("[SmartGitServer] About to serve_connection"); | ||
| 599 | if let Err(e) = http1::Builder::new() | 599 | if let Err(e) = http1::Builder::new() |
| 600 | .serve_connection(io, service) | 600 | .serve_connection(io, service) |
| 601 | .await | 601 | .await |
| @@ -605,7 +605,6 @@ impl SmartGitServer { | |||
| 605 | eprintln!("SmartGitServer connection error: {}", e); | 605 | eprintln!("SmartGitServer connection error: {}", e); |
| 606 | } | 606 | } |
| 607 | } | 607 | } |
| 608 | eprintln!("[SmartGitServer] Connection handler finished"); | ||
| 609 | }); | 608 | }); |
| 610 | } | 609 | } |
| 611 | Err(e) => { | 610 | Err(e) => { |
| @@ -615,20 +614,16 @@ impl SmartGitServer { | |||
| 615 | } | 614 | } |
| 616 | _ = &mut shutdown_rx => { | 615 | _ = &mut shutdown_rx => { |
| 617 | // Shutdown signal received | 616 | // Shutdown signal received |
| 618 | eprintln!("[SmartGitServer] Shutdown signal received"); | ||
| 619 | break; | 617 | break; |
| 620 | } | 618 | } |
| 621 | } | 619 | } |
| 622 | } | 620 | } |
| 623 | eprintln!("[SmartGitServer] Server loop exited"); | ||
| 624 | }); | 621 | }); |
| 625 | 622 | ||
| 626 | let url = format!("http://127.0.0.1:{}", port); | 623 | let url = format!("http://127.0.0.1:{}", port); |
| 627 | 624 | ||
| 628 | println!("[SmartGitServer::start] Waiting for server to be ready on port {}", port); | ||
| 629 | // 6. Wait for server to be ready | 625 | // 6. Wait for server to be ready |
| 630 | wait_for_server_ready(port).await; | 626 | wait_for_server_ready(port).await; |
| 631 | println!("[SmartGitServer::start] Server is ready!"); | ||
| 632 | 627 | ||
| 633 | Self { | 628 | Self { |
| 634 | shutdown_tx: Some(shutdown_tx), | 629 | shutdown_tx: Some(shutdown_tx), |
| @@ -684,9 +679,6 @@ async fn handle_smart_request( | |||
| 684 | let query = req.uri().query().unwrap_or(""); | 679 | let query = req.uri().query().unwrap_or(""); |
| 685 | let method = req.method(); | 680 | let method = req.method(); |
| 686 | 681 | ||
| 687 | println!("[SmartGitServer] {} {} query={}", method, path, query); | ||
| 688 | eprintln!("[SmartGitServer] {} {} query={}", method, path, query); | ||
| 689 | |||
| 690 | // Extract Git-Protocol header (for protocol version 2) | 682 | // Extract Git-Protocol header (for protocol version 2) |
| 691 | // We need to clone it to avoid borrowing issues when moving req | 683 | // We need to clone it to avoid borrowing issues when moving req |
| 692 | let git_protocol = req | 684 | let git_protocol = req |
| @@ -695,10 +687,6 @@ async fn handle_smart_request( | |||
| 695 | .and_then(|v| v.to_str().ok()) | 687 | .and_then(|v| v.to_str().ok()) |
| 696 | .map(|s| s.to_string()); | 688 | .map(|s| s.to_string()); |
| 697 | 689 | ||
| 698 | if let Some(ref proto) = git_protocol { | ||
| 699 | eprintln!("[SmartGitServer] Git-Protocol: {}", proto); | ||
| 700 | } | ||
| 701 | |||
| 702 | // Route: GET /info/refs?service=git-upload-pack | 690 | // Route: GET /info/refs?service=git-upload-pack |
| 703 | if method == hyper::Method::GET && path.ends_with("/info/refs") { | 691 | if method == hyper::Method::GET && path.ends_with("/info/refs") { |
| 704 | // Parse service from query string | 692 | // Parse service from query string |
| @@ -714,7 +702,6 @@ async fn handle_smart_request( | |||
| 714 | 702 | ||
| 715 | match service { | 703 | match service { |
| 716 | Some("git-upload-pack") => { | 704 | Some("git-upload-pack") => { |
| 717 | eprintln!("[SmartGitServer] Handling info/refs for upload-pack"); | ||
| 718 | return handle_info_refs_upload_pack(repo_path, git_protocol.as_deref()).await; | 705 | return handle_info_refs_upload_pack(repo_path, git_protocol.as_deref()).await; |
| 719 | } | 706 | } |
| 720 | Some("git-receive-pack") => { | 707 | Some("git-receive-pack") => { |
| @@ -735,7 +722,6 @@ async fn handle_smart_request( | |||
| 735 | 722 | ||
| 736 | // Route: POST /git-upload-pack | 723 | // Route: POST /git-upload-pack |
| 737 | if method == hyper::Method::POST && path.ends_with("/git-upload-pack") { | 724 | if method == hyper::Method::POST && path.ends_with("/git-upload-pack") { |
| 738 | eprintln!("[SmartGitServer] Handling POST /git-upload-pack"); | ||
| 739 | return handle_upload_pack(req, repo_path, git_protocol.as_deref()).await; | 725 | return handle_upload_pack(req, repo_path, git_protocol.as_deref()).await; |
| 740 | } | 726 | } |
| 741 | 727 | ||
| @@ -986,31 +972,20 @@ mod smart_git_server_tests { | |||
| 986 | 972 | ||
| 987 | #[tokio::test] | 973 | #[tokio::test] |
| 988 | async fn test_smart_git_server_ls_remote() { | 974 | async fn test_smart_git_server_ls_remote() { |
| 989 | println!("[TEST] Starting test_smart_git_server_ls_remote"); | ||
| 990 | eprintln!("[TEST] Starting test_smart_git_server_ls_remote"); | ||
| 991 | |||
| 992 | // Create a test repo | 975 | // Create a test repo |
| 993 | let temp_dir = tempfile::tempdir().expect("Failed to create temp dir"); | 976 | let temp_dir = tempfile::tempdir().expect("Failed to create temp dir"); |
| 994 | println!("[TEST] Created temp dir"); | ||
| 995 | let commit_hash = create_test_repo_with_commit(temp_dir.path(), CommitVariant::StateTest) | 977 | let commit_hash = create_test_repo_with_commit(temp_dir.path(), CommitVariant::StateTest) |
| 996 | .expect("Failed to create test repo"); | 978 | .expect("Failed to create test repo"); |
| 997 | println!("[TEST] Created test repo with commit {}", commit_hash); | ||
| 998 | 979 | ||
| 999 | // Start server | 980 | // Start server |
| 1000 | println!("[TEST] About to start SmartGitServer"); | ||
| 1001 | let server = SmartGitServer::start(temp_dir.path()).await; | 981 | let server = SmartGitServer::start(temp_dir.path()).await; |
| 1002 | println!("[TEST] Server started at {}", server.url()); | ||
| 1003 | |||
| 1004 | // Give the server loop task a chance to print | ||
| 1005 | tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; | ||
| 1006 | 982 | ||
| 1007 | // Run git ls-remote against the server | 983 | // Run git ls-remote against the server (using tokio::process::Command) |
| 1008 | println!("[TEST] Running git ls-remote {}", server.url()); | 984 | let output = tokio::process::Command::new("git") |
| 1009 | let output = Command::new("git") | ||
| 1010 | .args(["ls-remote", server.url()]) | 985 | .args(["ls-remote", server.url()]) |
| 1011 | .output() | 986 | .output() |
| 987 | .await | ||
| 1012 | .expect("Failed to run git ls-remote"); | 988 | .expect("Failed to run git ls-remote"); |
| 1013 | println!("[TEST] git ls-remote completed"); | ||
| 1014 | 989 | ||
| 1015 | assert!( | 990 | assert!( |
| 1016 | output.status.success(), | 991 | output.status.success(), |
| @@ -1050,26 +1025,29 @@ mod smart_git_server_tests { | |||
| 1050 | let dest_dir = tempfile::tempdir().expect("Failed to create dest dir"); | 1025 | let dest_dir = tempfile::tempdir().expect("Failed to create dest dir"); |
| 1051 | 1026 | ||
| 1052 | // Initialize empty repo | 1027 | // Initialize empty repo |
| 1053 | let output = Command::new("git") | 1028 | let output = tokio::process::Command::new("git") |
| 1054 | .args(["init"]) | 1029 | .args(["init"]) |
| 1055 | .current_dir(dest_dir.path()) | 1030 | .current_dir(dest_dir.path()) |
| 1056 | .output() | 1031 | .output() |
| 1032 | .await | ||
| 1057 | .expect("Failed to init dest repo"); | 1033 | .expect("Failed to init dest repo"); |
| 1058 | assert!(output.status.success()); | 1034 | assert!(output.status.success()); |
| 1059 | 1035 | ||
| 1060 | // Add the server as a remote | 1036 | // Add the server as a remote |
| 1061 | let output = Command::new("git") | 1037 | let output = tokio::process::Command::new("git") |
| 1062 | .args(["remote", "add", "origin", server.url()]) | 1038 | .args(["remote", "add", "origin", server.url()]) |
| 1063 | .current_dir(dest_dir.path()) | 1039 | .current_dir(dest_dir.path()) |
| 1064 | .output() | 1040 | .output() |
| 1041 | .await | ||
| 1065 | .expect("Failed to add remote"); | 1042 | .expect("Failed to add remote"); |
| 1066 | assert!(output.status.success()); | 1043 | assert!(output.status.success()); |
| 1067 | 1044 | ||
| 1068 | // Fetch from the server | 1045 | // Fetch from the server |
| 1069 | let output = Command::new("git") | 1046 | let output = tokio::process::Command::new("git") |
| 1070 | .args(["fetch", "origin"]) | 1047 | .args(["fetch", "origin"]) |
| 1071 | .current_dir(dest_dir.path()) | 1048 | .current_dir(dest_dir.path()) |
| 1072 | .output() | 1049 | .output() |
| 1050 | .await | ||
| 1073 | .expect("Failed to fetch"); | 1051 | .expect("Failed to fetch"); |
| 1074 | 1052 | ||
| 1075 | assert!( | 1053 | assert!( |
| @@ -1079,10 +1057,11 @@ mod smart_git_server_tests { | |||
| 1079 | ); | 1057 | ); |
| 1080 | 1058 | ||
| 1081 | // Verify the commit was fetched | 1059 | // Verify the commit was fetched |
| 1082 | let output = Command::new("git") | 1060 | let output = tokio::process::Command::new("git") |
| 1083 | .args(["rev-parse", "origin/main"]) | 1061 | .args(["rev-parse", "origin/main"]) |
| 1084 | .current_dir(dest_dir.path()) | 1062 | .current_dir(dest_dir.path()) |
| 1085 | .output() | 1063 | .output() |
| 1064 | .await | ||
| 1086 | .expect("Failed to rev-parse"); | 1065 | .expect("Failed to rev-parse"); |
| 1087 | 1066 | ||
| 1088 | assert!(output.status.success()); | 1067 | assert!(output.status.success()); |
| @@ -1111,26 +1090,29 @@ mod smart_git_server_tests { | |||
| 1111 | let dest_dir = tempfile::tempdir().expect("Failed to create dest dir"); | 1090 | let dest_dir = tempfile::tempdir().expect("Failed to create dest dir"); |
| 1112 | 1091 | ||
| 1113 | // Initialize empty repo | 1092 | // Initialize empty repo |
| 1114 | let output = Command::new("git") | 1093 | let output = tokio::process::Command::new("git") |
| 1115 | .args(["init"]) | 1094 | .args(["init"]) |
| 1116 | .current_dir(dest_dir.path()) | 1095 | .current_dir(dest_dir.path()) |
| 1117 | .output() | 1096 | .output() |
| 1097 | .await | ||
| 1118 | .expect("Failed to init dest repo"); | 1098 | .expect("Failed to init dest repo"); |
| 1119 | assert!(output.status.success()); | 1099 | assert!(output.status.success()); |
| 1120 | 1100 | ||
| 1121 | // Add the server as a remote | 1101 | // Add the server as a remote |
| 1122 | let output = Command::new("git") | 1102 | let output = tokio::process::Command::new("git") |
| 1123 | .args(["remote", "add", "origin", server.url()]) | 1103 | .args(["remote", "add", "origin", server.url()]) |
| 1124 | .current_dir(dest_dir.path()) | 1104 | .current_dir(dest_dir.path()) |
| 1125 | .output() | 1105 | .output() |
| 1106 | .await | ||
| 1126 | .expect("Failed to add remote"); | 1107 | .expect("Failed to add remote"); |
| 1127 | assert!(output.status.success()); | 1108 | assert!(output.status.success()); |
| 1128 | 1109 | ||
| 1129 | // Shallow fetch from the server - THIS IS WHAT PURGATORY SYNC USES | 1110 | // Shallow fetch from the server - THIS IS WHAT PURGATORY SYNC USES |
| 1130 | let output = Command::new("git") | 1111 | let output = tokio::process::Command::new("git") |
| 1131 | .args(["fetch", "--depth=1", "origin", &commit_hash]) | 1112 | .args(["fetch", "--depth=1", "origin", &commit_hash]) |
| 1132 | .current_dir(dest_dir.path()) | 1113 | .current_dir(dest_dir.path()) |
| 1133 | .output() | 1114 | .output() |
| 1115 | .await | ||
| 1134 | .expect("Failed to fetch"); | 1116 | .expect("Failed to fetch"); |
| 1135 | 1117 | ||
| 1136 | assert!( | 1118 | assert!( |
| @@ -1140,10 +1122,11 @@ mod smart_git_server_tests { | |||
| 1140 | ); | 1122 | ); |
| 1141 | 1123 | ||
| 1142 | // Verify the commit was fetched | 1124 | // Verify the commit was fetched |
| 1143 | let output = Command::new("git") | 1125 | let output = tokio::process::Command::new("git") |
| 1144 | .args(["cat-file", "-t", &commit_hash]) | 1126 | .args(["cat-file", "-t", &commit_hash]) |
| 1145 | .current_dir(dest_dir.path()) | 1127 | .current_dir(dest_dir.path()) |
| 1146 | .output() | 1128 | .output() |
| 1129 | .await | ||
| 1147 | .expect("Failed to cat-file"); | 1130 | .expect("Failed to cat-file"); |
| 1148 | 1131 | ||
| 1149 | assert!( | 1132 | assert!( |
diff --git a/tests/common/mock_relay.rs b/tests/common/mock_relay.rs index 123c29e..b6376a7 100644 --- a/tests/common/mock_relay.rs +++ b/tests/common/mock_relay.rs | |||
| @@ -72,14 +72,35 @@ impl MockRelay { | |||
| 72 | /// The relay accepts all events without validation and stores them | 72 | /// The relay accepts all events without validation and stores them |
| 73 | /// in an in-memory database. | 73 | /// in an in-memory database. |
| 74 | pub async fn start() -> Self { | 74 | pub async fn start() -> Self { |
| 75 | let port = find_free_port(); | 75 | // Create and bind listener (eliminates port race condition) |
| 76 | Self::start_on_port(port).await | 76 | let std_listener = std::net::TcpListener::bind("127.0.0.1:0") |
| 77 | .expect("Failed to bind to random port"); | ||
| 78 | let port = std_listener | ||
| 79 | .local_addr() | ||
| 80 | .expect("Failed to get local addr") | ||
| 81 | .port(); | ||
| 82 | |||
| 83 | // Convert to tokio listener (keeps port bound) | ||
| 84 | std_listener | ||
| 85 | .set_nonblocking(true) | ||
| 86 | .expect("Failed to set non-blocking"); | ||
| 87 | let listener = TcpListener::from_std(std_listener) | ||
| 88 | .expect("Failed to convert to tokio listener"); | ||
| 89 | |||
| 90 | Self::start_with_listener(listener, port).await | ||
| 77 | } | 91 | } |
| 78 | 92 | ||
| 79 | /// Start a mock relay on a specific port. | 93 | /// Start a mock relay on a specific port. |
| 80 | pub async fn start_on_port(port: u16) -> Self { | 94 | pub async fn start_on_port(port: u16) -> Self { |
| 81 | let addr: SocketAddr = ([127, 0, 0, 1], port).into(); | 95 | let addr: SocketAddr = ([127, 0, 0, 1], port).into(); |
| 96 | let listener = TcpListener::bind(addr) | ||
| 97 | .await | ||
| 98 | .expect("Failed to bind to address"); | ||
| 99 | Self::start_with_listener(listener, port).await | ||
| 100 | } | ||
| 82 | 101 | ||
| 102 | /// Internal method to start the relay with an existing listener. | ||
| 103 | async fn start_with_listener(listener: TcpListener, port: u16) -> Self { | ||
| 83 | // Create a simple relay with no write policy (accepts all events) | 104 | // Create a simple relay with no write policy (accepts all events) |
| 84 | let relay = LocalRelayBuilder::default().build(); | 105 | let relay = LocalRelayBuilder::default().build(); |
| 85 | 106 | ||
| @@ -89,11 +110,6 @@ impl MockRelay { | |||
| 89 | // Clone relay for the server task | 110 | // Clone relay for the server task |
| 90 | let server_relay = relay.clone(); | 111 | let server_relay = relay.clone(); |
| 91 | 112 | ||
| 92 | // Start the HTTP/WebSocket server | ||
| 93 | let listener = TcpListener::bind(addr) | ||
| 94 | .await | ||
| 95 | .expect("Failed to bind to address"); | ||
| 96 | |||
| 97 | let handle = tokio::spawn(async move { | 113 | let handle = tokio::spawn(async move { |
| 98 | loop { | 114 | loop { |
| 99 | tokio::select! { | 115 | tokio::select! { |
| @@ -245,19 +261,6 @@ fn derive_accept_key(request_key: &[u8]) -> String { | |||
| 245 | base64::Engine::encode(&base64::engine::general_purpose::STANDARD, hash.as_byte_array()) | 261 | base64::Engine::encode(&base64::engine::general_purpose::STANDARD, hash.as_byte_array()) |
| 246 | } | 262 | } |
| 247 | 263 | ||
| 248 | /// Find a free port to use for the server. | ||
| 249 | fn find_free_port() -> u16 { | ||
| 250 | use std::net::TcpListener; | ||
| 251 | |||
| 252 | let listener = TcpListener::bind("127.0.0.1:0").expect("Failed to bind to random port"); | ||
| 253 | let port = listener | ||
| 254 | .local_addr() | ||
| 255 | .expect("Failed to get local addr") | ||
| 256 | .port(); | ||
| 257 | drop(listener); | ||
| 258 | port | ||
| 259 | } | ||
| 260 | |||
| 261 | /// Wait for the server to be ready to accept connections. | 264 | /// Wait for the server to be ready to accept connections. |
| 262 | async fn wait_for_server_ready(port: u16) { | 265 | async fn wait_for_server_ready(port: u16) { |
| 263 | let max_attempts = 50; // 5 seconds total | 266 | let max_attempts = 50; // 5 seconds total |