1
1
//! A mock distribution server used by tests/cli-v1.rs and
2
2
//! tests/cli-v2.rs
3
-
4
- use crate :: mock:: dist:: {
5
- change_channel_date, ManifestVersion , MockChannel , MockComponent , MockDistServer , MockPackage ,
6
- MockTargetedPackage ,
7
- } ;
8
- use crate :: mock:: topical_doc_data;
9
- use crate :: mock:: { MockComponentBuilder , MockFile , MockInstallerBuilder } ;
10
- use lazy_static:: lazy_static;
11
3
use std:: cell:: RefCell ;
12
4
use std:: collections:: HashMap ;
13
5
use std:: env;
@@ -18,8 +10,21 @@ use std::io;
18
10
use std:: path:: { Path , PathBuf } ;
19
11
use std:: process:: Command ;
20
12
use std:: sync:: Arc ;
13
+
14
+ use lazy_static:: lazy_static;
21
15
use url:: Url ;
22
16
17
+ use rustup:: cli:: rustup_mode;
18
+ use rustup:: currentprocess;
19
+ use rustup:: utils:: utils;
20
+
21
+ use crate :: mock:: dist:: {
22
+ change_channel_date, ManifestVersion , MockChannel , MockComponent , MockDistServer , MockPackage ,
23
+ MockTargetedPackage ,
24
+ } ;
25
+ use crate :: mock:: topical_doc_data;
26
+ use crate :: mock:: { MockComponentBuilder , MockFile , MockInstallerBuilder } ;
27
+
23
28
/// The configuration used by the tests in this module
24
29
pub struct Config {
25
30
/// Where we put the rustup / rustc / cargo bins
@@ -363,6 +368,12 @@ fn print_indented(heading: &str, text: &str) {
363
368
) ;
364
369
}
365
370
371
+ pub struct Output {
372
+ pub status : Option < i32 > ,
373
+ pub stdout : Vec < u8 > ,
374
+ pub stderr : Vec < u8 > ,
375
+ }
376
+
366
377
#[ derive( Debug ) ]
367
378
pub struct SanitizedOutput {
368
379
pub ok : bool ,
@@ -383,7 +394,36 @@ where
383
394
cmd
384
395
}
385
396
386
- pub fn env ( config : & Config , cmd : & mut Command ) {
397
+ pub trait Env {
398
+ fn env < K , V > ( & mut self , key : K , val : V )
399
+ where
400
+ K : AsRef < OsStr > ,
401
+ V : AsRef < OsStr > ;
402
+ }
403
+
404
+ impl Env for Command {
405
+ fn env < K , V > ( & mut self , key : K , val : V )
406
+ where
407
+ K : AsRef < OsStr > ,
408
+ V : AsRef < OsStr > ,
409
+ {
410
+ self . env ( key, val) ;
411
+ }
412
+ }
413
+
414
+ impl Env for HashMap < String , String > {
415
+ fn env < K , V > ( & mut self , key : K , val : V )
416
+ where
417
+ K : AsRef < OsStr > ,
418
+ V : AsRef < OsStr > ,
419
+ {
420
+ let key = key. as_ref ( ) . to_os_string ( ) . into_string ( ) . unwrap ( ) ;
421
+ let val = val. as_ref ( ) . to_os_string ( ) . into_string ( ) . unwrap ( ) ;
422
+ self . insert ( key, val) ;
423
+ }
424
+ }
425
+
426
+ pub fn env < E : Env > ( config : & Config , cmd : & mut E ) {
387
427
// Ensure PATH is prefixed with the rustup-exe directory
388
428
let prev_path = env:: var_os ( "PATH" ) ;
389
429
let mut new_path = config. exedir . clone ( ) . into_os_string ( ) ;
@@ -442,7 +482,111 @@ pub fn cmd_lock() -> &'static RwLock<()> {
442
482
& LOCK
443
483
}
444
484
485
+ fn allow_inprocess < I , A > ( name : & str , args : I ) -> bool
486
+ where
487
+ I : IntoIterator < Item = A > ,
488
+ A : AsRef < OsStr > ,
489
+ {
490
+ // Only the rustup alias is currently ready for in-process testing:
491
+ // - -init performs self-updates which monkey with global external state.
492
+ // - proxies themselves behave appropriately the proxied output needs to be
493
+ // collected for assertions to be made on it as our tests traverse layers.
494
+ // - self update executions cannot run in-process because on windows the
495
+ // process replacement dance would replace the test process.
496
+ if name != "rustup" {
497
+ return false ;
498
+ }
499
+ let mut is_update = false ;
500
+ let mut no_self_update = false ;
501
+ let mut self_cmd = false ;
502
+ let mut run = false ;
503
+ for arg in args {
504
+ if arg. as_ref ( ) == "update" {
505
+ is_update = true ;
506
+ } else if arg. as_ref ( ) == "--no-self-update" {
507
+ no_self_update = true ;
508
+ } else if arg. as_ref ( ) == "self" {
509
+ self_cmd = true ;
510
+ } else if arg. as_ref ( ) == "run" {
511
+ run = true ;
512
+ }
513
+ }
514
+ !( run || self_cmd || ( is_update && !no_self_update) )
515
+ }
516
+
445
517
pub fn run < I , A > ( config : & Config , name : & str , args : I , env : & [ ( & str , & str ) ] ) -> SanitizedOutput
518
+ where
519
+ I : IntoIterator < Item = A > + Clone ,
520
+ A : AsRef < OsStr > ,
521
+ {
522
+ let inprocess = allow_inprocess ( name, args. clone ( ) ) ;
523
+ let out = if inprocess {
524
+ run_inprocess ( config, name, args, env)
525
+ } else {
526
+ run_subprocess ( config, name, args, env)
527
+ } ;
528
+ let output = SanitizedOutput {
529
+ ok : if let Some ( 0 ) = out. status {
530
+ true
531
+ } else {
532
+ false
533
+ } ,
534
+ stdout : String :: from_utf8 ( out. stdout ) . unwrap ( ) ,
535
+ stderr : String :: from_utf8 ( out. stderr ) . unwrap ( ) ,
536
+ } ;
537
+
538
+ println ! ( "inprocess: {}" , inprocess) ;
539
+ println ! ( "status: {:?}" , out. status) ;
540
+ println ! ( "----- stdout\n {}" , output. stdout) ;
541
+ println ! ( "----- stderr\n {}" , output. stderr) ;
542
+
543
+ output
544
+ }
545
+
546
+ pub fn run_inprocess < I , A > ( config : & Config , name : & str , args : I , env : & [ ( & str , & str ) ] ) -> Output
547
+ where
548
+ I : IntoIterator < Item = A > ,
549
+ A : AsRef < OsStr > ,
550
+ {
551
+ // should we use vars_os, or skip over non-stringable vars? This is test
552
+ // code after all...
553
+ let mut vars: HashMap < String , String > = HashMap :: default ( ) ;
554
+ self :: env ( config, & mut vars) ;
555
+ vars. extend ( env. iter ( ) . map ( |( k, v) | ( k. to_string ( ) , v. to_string ( ) ) ) ) ;
556
+ let mut arg_strings: Vec < Box < str > > = Vec :: new ( ) ;
557
+ arg_strings. push ( name. to_owned ( ) . into_boxed_str ( ) ) ;
558
+ for arg in args {
559
+ arg_strings. push (
560
+ arg. as_ref ( )
561
+ . to_os_string ( )
562
+ . into_string ( )
563
+ . unwrap ( )
564
+ . into_boxed_str ( ) ,
565
+ ) ;
566
+ }
567
+ let tp = Box :: new ( currentprocess:: TestProcess :: new (
568
+ & * config. workdir . borrow ( ) ,
569
+ & arg_strings,
570
+ vars,
571
+ "" ,
572
+ ) ) ;
573
+ let process_res = currentprocess:: with ( tp. clone ( ) , || rustup_mode:: main ( ) ) ;
574
+ // convert Err's into an ec
575
+ let ec = match process_res {
576
+ Ok ( process_res) => process_res,
577
+ Err ( e) => {
578
+ currentprocess:: with ( tp. clone ( ) , || rustup:: cli:: common:: report_error ( & e) ) ;
579
+ utils:: ExitCode ( 1 )
580
+ }
581
+ } ;
582
+ Output {
583
+ status : Some ( ec. 0 ) ,
584
+ stderr : ( * tp) . get_stderr ( ) ,
585
+ stdout : ( * tp) . get_stdout ( ) ,
586
+ }
587
+ }
588
+
589
+ pub fn run_subprocess < I , A > ( config : & Config , name : & str , args : I , env : & [ ( & str , & str ) ] ) -> Output
446
590
where
447
591
I : IntoIterator < Item = A > ,
448
592
A : AsRef < OsStr > ,
@@ -452,7 +596,6 @@ where
452
596
cmd. env ( env. 0 , env. 1 ) ;
453
597
}
454
598
455
- println ! ( "running {:?}" , cmd) ;
456
599
let mut retries = 8 ;
457
600
let out = loop {
458
601
let lock = cmd_lock ( ) . read ( ) . unwrap ( ) ;
@@ -474,18 +617,11 @@ where
474
617
}
475
618
}
476
619
} ;
477
-
478
- let output = SanitizedOutput {
479
- ok : out. status . success ( ) ,
480
- stdout : String :: from_utf8 ( out. stdout ) . unwrap ( ) ,
481
- stderr : String :: from_utf8 ( out. stderr ) . unwrap ( ) ,
482
- } ;
483
-
484
- println ! ( "status: {}" , out. status) ;
485
- println ! ( "----- stdout\n {}" , output. stdout) ;
486
- println ! ( "----- stderr\n {}" , output. stderr) ;
487
-
488
- output
620
+ Output {
621
+ status : out. status . code ( ) ,
622
+ stdout : out. stdout ,
623
+ stderr : out. stderr ,
624
+ }
489
625
}
490
626
491
627
#[ derive( Copy , Clone , Eq , PartialEq ) ]
0 commit comments