@@ -6,6 +6,7 @@ use std::io;
6
6
use std:: io:: prelude:: * ;
7
7
use std:: net:: TcpListener ;
8
8
use std:: path:: { Path , PathBuf } ;
9
+ use std:: process:: Stdio ;
9
10
use std:: thread;
10
11
use std:: time:: SystemTime ;
11
12
@@ -2323,3 +2324,87 @@ LLVM version: 9.0
2323
2324
assert_eq ! ( check( "beta1" , true ) , beta1_name) ;
2324
2325
assert_eq ! ( check( "nightly1" , true ) , nightly1_name) ;
2325
2326
}
2327
+
2328
+ #[ cargo_test]
2329
+ fn linking_interrupted ( ) {
2330
+ // Interrupt during the linking phase shouldn't leave test executable as "fresh".
2331
+
2332
+ let listener = TcpListener :: bind ( "127.0.0.1:0" ) . unwrap ( ) ;
2333
+ let addr = listener. local_addr ( ) . unwrap ( ) ;
2334
+
2335
+ // Create a linker that we can interrupt.
2336
+ let linker = project ( )
2337
+ . at ( "linker" )
2338
+ . file ( "Cargo.toml" , & basic_manifest ( "linker" , "1.0.0" ) )
2339
+ . file (
2340
+ "src/main.rs" ,
2341
+ & r#"
2342
+ use std::io::Read;
2343
+
2344
+ fn main() {
2345
+ // Figure out the output filename.
2346
+ let output = match std::env::args().find(|a| a.starts_with("/OUT:")) {
2347
+ Some(s) => s[5..].to_string(),
2348
+ None => {
2349
+ let mut args = std::env::args();
2350
+ loop {
2351
+ if args.next().unwrap() == "-o" {
2352
+ break;
2353
+ }
2354
+ }
2355
+ args.next().unwrap()
2356
+ }
2357
+ };
2358
+ std::fs::remove_file(&output).unwrap();
2359
+ std::fs::write(&output, "").unwrap();
2360
+ // Tell the test that we are ready to be interrupted.
2361
+ let mut socket = std::net::TcpStream::connect("__ADDR__").unwrap();
2362
+ // Wait for the test to tell us to exit.
2363
+ let _ = socket.read(&mut [0; 1]);
2364
+ }
2365
+ "#
2366
+ . replace ( "__ADDR__" , & addr. to_string ( ) ) ,
2367
+ )
2368
+ . build ( ) ;
2369
+ linker. cargo ( "build" ) . run ( ) ;
2370
+
2371
+ // Build it once so that the fingerprint gets saved to disk.
2372
+ let p = project ( )
2373
+ . file ( "src/lib.rs" , "" )
2374
+ . file ( "tests/t1.rs" , "" )
2375
+ . build ( ) ;
2376
+ p. cargo ( "test --test t1 --no-run" ) . run ( ) ;
2377
+ // Make a change, start a build, then interrupt it.
2378
+ p. change_file ( "src/lib.rs" , "// modified" ) ;
2379
+ let linker_env = format ! (
2380
+ "CARGO_TARGET_{}_LINKER" ,
2381
+ rustc_host( ) . to_uppercase( ) . replace( '-' , "_" )
2382
+ ) ;
2383
+ let mut cmd = p
2384
+ . cargo ( "test --test t1 --no-run" )
2385
+ . env ( & linker_env, linker. bin ( "linker" ) )
2386
+ . build_command ( ) ;
2387
+ let mut child = cmd
2388
+ . stdout ( Stdio :: null ( ) )
2389
+ . stderr ( Stdio :: null ( ) )
2390
+ . spawn ( )
2391
+ . unwrap ( ) ;
2392
+ // Wait for linking to start.
2393
+ let mut conn = listener. accept ( ) . unwrap ( ) . 0 ;
2394
+
2395
+ // Interrupt the child.
2396
+ child. kill ( ) . unwrap ( ) ;
2397
+ // Note: rustc and the linker are still running, let them exit here.
2398
+ conn. write ( b"X" ) . unwrap ( ) ;
2399
+
2400
+ // Build again, shouldn't be fresh.
2401
+ p. cargo ( "test --test t1" )
2402
+ . with_stderr (
2403
+ "\
2404
+ [COMPILING] foo [..]
2405
+ [FINISHED] [..]
2406
+ [RUNNING] target/debug/deps/t1[..]
2407
+ " ,
2408
+ )
2409
+ . run ( ) ;
2410
+ }
0 commit comments