11use std:: { fs, path:: PathBuf , process:: Command , time:: Duration } ;
22
3+ use rustup:: dist:: manifestation:: CHECKPOINT_UPDATE_BEFORE_METADATA ;
4+ use rustup:: install:: {
5+ CHECKPOINT_INSTALL_AFTER_PUBLISH , CHECKPOINT_INSTALL_BEFORE_PUBLISH , STAGING_DIR_PREFIX ,
6+ } ;
37use rustup:: test:: { CliTestContext , Scenario , this_host_tuple} ;
48use wait_timeout:: ChildExt ;
59
@@ -30,6 +34,13 @@ fn nightly_update_hash_path(cx: &CliTestContext) -> PathBuf {
3034 . join ( format ! ( "nightly-{}" , this_host_tuple( ) ) )
3135}
3236
37+ fn nightly_staging_root ( cx : & CliTestContext ) -> PathBuf {
38+ cx. config
39+ . rustupdir
40+ . join ( "toolchains" )
41+ . join ( format ! ( "{STAGING_DIR_PREFIX}nightly-{}" , this_host_tuple( ) ) )
42+ }
43+
3344fn staging_paths ( cx : & CliTestContext ) -> Vec < PathBuf > {
3445 fs:: read_dir ( cx. config . rustupdir . join ( "toolchains" ) )
3546 . expect ( "failed to read toolchains directory" )
@@ -66,15 +77,13 @@ rustc-[HOST_TUPLE]
6677
6778async fn assert_unpublished_install_can_be_retried ( checkpoint : & str ) {
6879 let cx = CliTestContext :: new ( Scenario :: SimpleV2 ) . await ;
69- let command = cx. config . cmd ( "rustup" , [ "toolchain" , "install" , "nightly" ] ) ;
70-
71- let status = cx. kill_at_checkpoint ( command, checkpoint) ;
80+ let status = cx. kill_at ( checkpoint, [ "rustup" , "toolchain" , "install" , "nightly" ] ) ;
7281 assert ! ( !status. success( ) ) ;
7382 assert ! (
7483 !nightly_path( & cx) . exists( ) ,
7584 "an interrupted staging operation published the toolchain"
7685 ) ;
77- assert_eq ! ( staging_paths( & cx) . len ( ) , 1 ) ;
86+ assert_eq ! ( staging_paths( & cx) , vec! [ nightly_staging_root ( & cx ) ] ) ;
7887 cx. config
7988 . expect ( [ "rustup" , "toolchain" , "list" ] )
8089 . await
@@ -89,12 +98,50 @@ async fn assert_unpublished_install_can_be_retried(checkpoint: &str) {
8998
9099#[ tokio:: test]
91100async fn interrupted_install_can_be_retried ( ) {
92- assert_unpublished_install_can_be_retried ( BEFORE_METADATA ) . await ;
101+ assert_unpublished_install_can_be_retried ( CHECKPOINT_UPDATE_BEFORE_METADATA ) . await ;
93102}
94103
95104#[ tokio:: test]
96105async fn interrupted_install_before_publication_can_be_retried ( ) {
97- assert_unpublished_install_can_be_retried ( BEFORE_PUBLISH ) . await ;
106+ assert_unpublished_install_can_be_retried ( CHECKPOINT_INSTALL_BEFORE_PUBLISH ) . await ;
107+ }
108+
109+ #[ tokio:: test]
110+ async fn interrupted_installs_do_not_accumulate_stages ( ) {
111+ let cx = CliTestContext :: new ( Scenario :: SimpleV2 ) . await ;
112+
113+ for _ in 0 ..2 {
114+ let status = cx. kill_at (
115+ CHECKPOINT_INSTALL_BEFORE_PUBLISH ,
116+ [ "rustup" , "toolchain" , "install" , "nightly" ] ,
117+ ) ;
118+ assert ! ( !status. success( ) ) ;
119+ assert_eq ! ( staging_paths( & cx) , vec![ nightly_staging_root( & cx) ] ) ;
120+ }
121+
122+ assert_completes_successfully ( cx. config . cmd ( "rustup" , [ "toolchain" , "install" , "nightly" ] ) ) ;
123+ assert ! ( staging_paths( & cx) . is_empty( ) ) ;
124+ assert_nightly_is_complete ( & cx) . await ;
125+ }
126+
127+ #[ tokio:: test]
128+ async fn stale_stage_is_reclaimed_by_the_next_install ( ) {
129+ let cx = CliTestContext :: new ( Scenario :: SimpleV2 ) . await ;
130+ let junk = nightly_staging_root ( & cx)
131+ . join ( "toolchain" )
132+ . join ( "bin" )
133+ . join ( "stale-junk" ) ;
134+ fs:: create_dir_all ( junk. parent ( ) . unwrap ( ) ) . unwrap ( ) ;
135+ fs:: write ( & junk, "junk" ) . unwrap ( ) ;
136+ fs:: write ( nightly_staging_root ( & cx) . join ( "update-hash" ) , "stale-hash" ) . unwrap ( ) ;
137+
138+ assert_completes_successfully ( cx. config . cmd ( "rustup" , [ "toolchain" , "install" , "nightly" ] ) ) ;
139+ assert ! ( staging_paths( & cx) . is_empty( ) ) ;
140+ assert ! (
141+ !nightly_path( & cx) . join( "bin" ) . join( "stale-junk" ) . exists( ) ,
142+ "contents of a stale stage leaked into the published toolchain"
143+ ) ;
144+ assert_nightly_is_complete ( & cx) . await ;
98145}
99146
100147#[ tokio:: test]
@@ -104,8 +151,10 @@ async fn unpublished_install_does_not_change_update_hash() {
104151 fs:: create_dir_all ( update_hash. parent ( ) . unwrap ( ) ) . unwrap ( ) ;
105152 fs:: write ( & update_hash, "stale-hash" ) . unwrap ( ) ;
106153
107- let command = cx. config . cmd ( "rustup" , [ "toolchain" , "install" , "nightly" ] ) ;
108- let status = cx. kill_at_checkpoint ( command, BEFORE_PUBLISH ) ;
154+ let status = cx. kill_at (
155+ CHECKPOINT_INSTALL_BEFORE_PUBLISH ,
156+ [ "rustup" , "toolchain" , "install" , "nightly" ] ,
157+ ) ;
109158
110159 assert ! ( !status. success( ) ) ;
111160 assert_eq ! ( fs:: read_to_string( update_hash) . unwrap( ) , "stale-hash" ) ;
@@ -115,9 +164,10 @@ async fn unpublished_install_does_not_change_update_hash() {
115164#[ tokio:: test]
116165async fn interrupted_install_after_publication_is_complete ( ) {
117166 let cx = CliTestContext :: new ( Scenario :: SimpleV2 ) . await ;
118- let command = cx. config . cmd ( "rustup" , [ "toolchain" , "install" , "nightly" ] ) ;
119-
120- let status = cx. kill_at_checkpoint ( command, AFTER_PUBLISH ) ;
167+ let status = cx. kill_at (
168+ CHECKPOINT_INSTALL_AFTER_PUBLISH ,
169+ [ "rustup" , "toolchain" , "install" , "nightly" ] ,
170+ ) ;
121171 assert ! ( !status. success( ) ) ;
122172 assert ! ( nightly_path( & cx) . is_dir( ) ) ;
123173 assert ! ( staging_paths( & cx) . is_empty( ) ) ;
@@ -163,16 +213,13 @@ async fn interrupted_update_can_be_retried() {
163213 . is_ok ( ) ;
164214
165215 cx. config . set_current_dist_date ( "2015-01-02" ) ;
166- let command = cx. config . cmd ( "rustup" , [ "update" , "nightly" ] ) ;
167- let status = cx. kill_at_checkpoint ( command, BEFORE_METADATA ) ;
216+ let status = cx. kill_at (
217+ CHECKPOINT_UPDATE_BEFORE_METADATA ,
218+ [ "rustup" , "update" , "nightly" ] ,
219+ ) ;
168220 assert ! ( !status. success( ) ) ;
169221
170222 assert_completes_successfully ( cx. config . cmd ( "rustup" , [ "update" , "nightly" ] ) ) ;
171223
172224 assert_nightly_is_complete ( & cx) . await ;
173225}
174-
175- const BEFORE_METADATA : & str = "manifestation-update-before-metadata" ;
176- const BEFORE_PUBLISH : & str = "install-before-publish" ;
177- const AFTER_PUBLISH : & str = "install-after-publish" ;
178- const STAGING_DIR_PREFIX : & str = "+rustup-staging-" ;
0 commit comments