@@ -61,19 +61,15 @@ mod shortcut;
61
61
62
62
use super :: { HttpServer , HttpServerHandle } ;
63
63
use std:: io:: Read ;
64
- use std:: net:: SocketAddr ;
64
+ use std:: net:: { SocketAddr , TcpListener } ;
65
65
use std:: path:: { Path , PathBuf } ;
66
66
use std:: process:: { Child , Command , Stdio } ;
67
- use std:: sync:: atomic:: AtomicU32 ;
67
+ use std:: sync:: atomic:: { AtomicU16 , AtomicU32 } ;
68
68
use std:: sync:: { Arc , Mutex } ;
69
69
use std:: thread;
70
70
use std:: time:: Duration ;
71
71
use triagebot:: test_record:: Activity ;
72
72
73
- /// TCP port that the triagebot binary should listen on.
74
- ///
75
- /// Increases by 1 for each test.
76
- static NEXT_TCP_PORT : AtomicU32 = AtomicU32 :: new ( 50000 ) ;
77
73
/// Counter used to give each test a unique sandbox directory in the
78
74
/// `target/tmp` directory.
79
75
static TEST_COUNTER : AtomicU32 = AtomicU32 :: new ( 1 ) ;
@@ -150,9 +146,7 @@ fn build(activities: Vec<Activity>) -> ServerTestCtx {
150
146
setup_postgres ( & db_dir) ;
151
147
152
148
let server = HttpServer :: new ( activities) ;
153
- // TODO: This is a poor way to choose a TCP port, as it could already
154
- // be in use by something else.
155
- let triagebot_port = NEXT_TCP_PORT . fetch_add ( 1 , std:: sync:: atomic:: Ordering :: SeqCst ) ;
149
+ let triagebot_port = next_triagebot_port ( ) ;
156
150
let mut child = Command :: new ( env ! ( "CARGO_BIN_EXE_triagebot" ) )
157
151
. env (
158
152
"GITHUB_API_TOKEN" ,
@@ -375,3 +369,24 @@ fn find_postgres() -> PathBuf {
375
369
Or, add them to your PATH."
376
370
) ;
377
371
}
372
+
373
+ /// Returns a free port for the next triagebot process to use.
374
+ fn next_triagebot_port ( ) -> u16 {
375
+ static NEXT_TCP_PORT : AtomicU16 = AtomicU16 :: new ( 50000 ) ;
376
+ loop {
377
+ // This depends on SO_REUSEADDR being set.
378
+ //
379
+ // This is inherently racey, as the port may become unavailable
380
+ // in-between the time it is checked here and triagebot actually binds
381
+ // to it.
382
+ //
383
+ // TODO: This may not work on Windows, may need investigation/fixing.
384
+ let triagebot_port = NEXT_TCP_PORT . fetch_add ( 1 , std:: sync:: atomic:: Ordering :: SeqCst ) ;
385
+ if triagebot_port == 0 {
386
+ panic ! ( "can't find port to listen on" ) ;
387
+ }
388
+ if TcpListener :: bind ( format ! ( "127.0.0.1:{triagebot_port}" ) ) . is_ok ( ) {
389
+ return triagebot_port;
390
+ }
391
+ }
392
+ }
0 commit comments