Skip to content

Commit 7b19a6e

Browse files
committed
Add some more publish timeout tests
1 parent 5bea4ab commit 7b19a6e

File tree

3 files changed

+198
-39
lines changed

3 files changed

+198
-39
lines changed

crates/cargo-test-support/src/publish.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ pub(crate) fn create_index_line(
189189
json.to_string()
190190
}
191191

192-
pub(crate) fn write_to_index(registry_path: &PathBuf, name: &str, line: String, local: bool) {
192+
pub(crate) fn write_to_index(registry_path: &Path, name: &str, line: String, local: bool) {
193193
let file = cargo_util::registry::make_dep_path(name, false);
194194

195195
// Write file/line in the index.

crates/cargo-test-support/src/registry.rs

Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::fmt;
1313
use std::fs::{self, File};
1414
use std::io::{BufRead, BufReader, Read, Write};
1515
use std::net::{SocketAddr, TcpListener, TcpStream};
16-
use std::path::PathBuf;
16+
use std::path::{Path, PathBuf};
1717
use std::thread::{self, JoinHandle};
1818
use tar::{Builder, Header};
1919
use time::format_description::well_known::Rfc3339;
@@ -98,6 +98,8 @@ pub struct RegistryBuilder {
9898
configure_registry: bool,
9999
/// API responders.
100100
custom_responders: HashMap<&'static str, Box<dyn Send + Fn(&Request, &HttpServer) -> Response>>,
101+
/// If nonzero, the git index update to be delayed by the given number of seconds.
102+
delayed_index_update: usize,
101103
}
102104

103105
pub struct TestRegistry {
@@ -157,6 +159,7 @@ impl RegistryBuilder {
157159
configure_registry: true,
158160
configure_token: true,
159161
custom_responders: HashMap::new(),
162+
delayed_index_update: 0,
160163
}
161164
}
162165

@@ -171,6 +174,13 @@ impl RegistryBuilder {
171174
self
172175
}
173176

177+
/// Configures the git index update to be delayed by the given number of seconds.
178+
#[must_use]
179+
pub fn delayed_index_update(mut self, delay: usize) -> Self {
180+
self.delayed_index_update = delay;
181+
self
182+
}
183+
174184
/// Sets whether or not to initialize as an alternative registry.
175185
#[must_use]
176186
pub fn alternative_named(mut self, alt: &str) -> Self {
@@ -265,6 +275,7 @@ impl RegistryBuilder {
265275
token.clone(),
266276
self.auth_required,
267277
self.custom_responders,
278+
self.delayed_index_update,
268279
);
269280
let index_url = if self.http_index {
270281
server.index_url()
@@ -591,6 +602,7 @@ pub struct HttpServer {
591602
token: Token,
592603
auth_required: bool,
593604
custom_responders: HashMap<&'static str, Box<dyn Send + Fn(&Request, &HttpServer) -> Response>>,
605+
delayed_index_update: usize,
594606
}
595607

596608
/// A helper struct that collects the arguments for [HttpServer::check_authorized].
@@ -613,6 +625,7 @@ impl HttpServer {
613625
&'static str,
614626
Box<dyn Send + Fn(&Request, &HttpServer) -> Response>,
615627
>,
628+
delayed_index_update: usize,
616629
) -> HttpServerHandle {
617630
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
618631
let addr = listener.local_addr().unwrap();
@@ -625,6 +638,7 @@ impl HttpServer {
625638
token,
626639
auth_required,
627640
custom_responders: api_responders,
641+
delayed_index_update,
628642
};
629643
let handle = Some(thread::spawn(move || server.start()));
630644
HttpServerHandle { addr, handle }
@@ -1040,49 +1054,23 @@ impl HttpServer {
10401054
return self.unauthorized(req);
10411055
}
10421056

1043-
// Write the `.crate`
10441057
let dst = self
10451058
.dl_path
10461059
.join(&new_crate.name)
10471060
.join(&new_crate.vers)
10481061
.join("download");
1049-
t!(fs::create_dir_all(dst.parent().unwrap()));
1050-
t!(fs::write(&dst, file));
1051-
1052-
let deps = new_crate
1053-
.deps
1054-
.iter()
1055-
.map(|dep| {
1056-
let (name, package) = match &dep.explicit_name_in_toml {
1057-
Some(explicit) => (explicit.to_string(), Some(dep.name.to_string())),
1058-
None => (dep.name.to_string(), None),
1059-
};
1060-
serde_json::json!({
1061-
"name": name,
1062-
"req": dep.version_req,
1063-
"features": dep.features,
1064-
"default_features": true,
1065-
"target": dep.target,
1066-
"optional": dep.optional,
1067-
"kind": dep.kind,
1068-
"registry": dep.registry,
1069-
"package": package,
1070-
})
1071-
})
1072-
.collect::<Vec<_>>();
1073-
1074-
let line = create_index_line(
1075-
serde_json::json!(new_crate.name),
1076-
&new_crate.vers,
1077-
deps,
1078-
&file_cksum,
1079-
new_crate.features,
1080-
false,
1081-
new_crate.links,
1082-
None,
1083-
);
10841062

1085-
write_to_index(&self.registry_path, &new_crate.name, line, false);
1063+
if self.delayed_index_update == 0 {
1064+
save_new_crate(dst, new_crate, file, file_cksum, &self.registry_path);
1065+
} else {
1066+
let delayed_index_update = self.delayed_index_update;
1067+
let registry_path = self.registry_path.clone();
1068+
let file = Vec::from(file);
1069+
thread::spawn(move || {
1070+
thread::sleep(std::time::Duration::new(delayed_index_update as u64, 0));
1071+
save_new_crate(dst, new_crate, &file, file_cksum, &registry_path);
1072+
});
1073+
}
10861074

10871075
self.ok(&req)
10881076
} else {
@@ -1095,6 +1083,53 @@ impl HttpServer {
10951083
}
10961084
}
10971085

1086+
fn save_new_crate(
1087+
dst: PathBuf,
1088+
new_crate: crates_io::NewCrate,
1089+
file: &[u8],
1090+
file_cksum: String,
1091+
registry_path: &Path,
1092+
) {
1093+
// Write the `.crate`
1094+
t!(fs::create_dir_all(dst.parent().unwrap()));
1095+
t!(fs::write(&dst, file));
1096+
1097+
let deps = new_crate
1098+
.deps
1099+
.iter()
1100+
.map(|dep| {
1101+
let (name, package) = match &dep.explicit_name_in_toml {
1102+
Some(explicit) => (explicit.to_string(), Some(dep.name.to_string())),
1103+
None => (dep.name.to_string(), None),
1104+
};
1105+
serde_json::json!({
1106+
"name": name,
1107+
"req": dep.version_req,
1108+
"features": dep.features,
1109+
"default_features": true,
1110+
"target": dep.target,
1111+
"optional": dep.optional,
1112+
"kind": dep.kind,
1113+
"registry": dep.registry,
1114+
"package": package,
1115+
})
1116+
})
1117+
.collect::<Vec<_>>();
1118+
1119+
let line = create_index_line(
1120+
serde_json::json!(new_crate.name),
1121+
&new_crate.vers,
1122+
deps,
1123+
&file_cksum,
1124+
new_crate.features,
1125+
false,
1126+
new_crate.links,
1127+
None,
1128+
);
1129+
1130+
write_to_index(registry_path, &new_crate.name, line, false);
1131+
}
1132+
10981133
impl Package {
10991134
/// Creates a new package builder.
11001135
/// Call `publish()` to finalize and build the package.

tests/testsuite/publish.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2702,3 +2702,127 @@ See [..]
27022702
)
27032703
.run();
27042704
}
2705+
2706+
#[cargo_test]
2707+
fn timeout_waiting_for_publish() {
2708+
// Publish doesn't happen within the timeout window.
2709+
let registry = registry::RegistryBuilder::new()
2710+
.http_api()
2711+
.delayed_index_update(20)
2712+
.build();
2713+
2714+
let p = project()
2715+
.file(
2716+
"Cargo.toml",
2717+
r#"
2718+
[package]
2719+
name = "delay"
2720+
version = "0.0.1"
2721+
authors = []
2722+
license = "MIT"
2723+
description = "foo"
2724+
"#,
2725+
)
2726+
.file("src/lib.rs", "")
2727+
.file(
2728+
".cargo/config.toml",
2729+
r#"
2730+
[publish]
2731+
timeout = 2
2732+
"#,
2733+
)
2734+
.build();
2735+
2736+
p.cargo("publish --no-verify -Zpublish-timeout")
2737+
.replace_crates_io(registry.index_url())
2738+
.masquerade_as_nightly_cargo(&["publish-timeout"])
2739+
.with_status(0)
2740+
// There may be a variable number of "Updating crates.io index" at the
2741+
// end, which is timing-dependent.
2742+
.with_stderr_contains(
2743+
"\
2744+
[UPDATING] crates.io index
2745+
[WARNING] manifest has no documentation, [..]
2746+
See [..]
2747+
[PACKAGING] delay v0.0.1 ([CWD])
2748+
[PACKAGED] [..] files, [..] ([..] compressed)
2749+
[UPLOADING] delay v0.0.1 ([CWD])
2750+
[UPDATING] crates.io index
2751+
[WAITING] on `delay` to propagate to crates.io index (ctrl-c to wait asynchronously)
2752+
",
2753+
)
2754+
.with_stderr_contains("warning: timed out waiting for `delay` to be in crates.io index")
2755+
.run();
2756+
}
2757+
2758+
#[cargo_test]
2759+
fn wait_for_git_publish() {
2760+
// Slow publish to an index with a git index.
2761+
let registry = registry::RegistryBuilder::new()
2762+
.http_api()
2763+
.delayed_index_update(5)
2764+
.build();
2765+
2766+
// Publish an earlier version
2767+
Package::new("delay", "0.0.1")
2768+
.file("src/lib.rs", "")
2769+
.publish();
2770+
2771+
let p = project()
2772+
.file(
2773+
"Cargo.toml",
2774+
r#"
2775+
[package]
2776+
name = "delay"
2777+
version = "0.0.2"
2778+
authors = []
2779+
license = "MIT"
2780+
description = "foo"
2781+
"#,
2782+
)
2783+
.file("src/lib.rs", "")
2784+
.build();
2785+
2786+
p.cargo("publish --no-verify")
2787+
.replace_crates_io(registry.index_url())
2788+
.with_status(0)
2789+
.with_stderr_contains(
2790+
"\
2791+
[UPDATING] crates.io index
2792+
[WARNING] manifest has no documentation, [..]
2793+
See [..]
2794+
[PACKAGING] delay v0.0.2 ([CWD])
2795+
[PACKAGED] [..] files, [..] ([..] compressed)
2796+
[UPLOADING] delay v0.0.2 ([CWD])
2797+
[UPDATING] crates.io index
2798+
[WAITING] on `delay` to propagate to crates.io index (ctrl-c to wait asynchronously)
2799+
",
2800+
)
2801+
// The exact number of updates is timing dependent. This just checks
2802+
// that at least a few show up.
2803+
.with_stderr_contains(
2804+
"\
2805+
[UPDATING] crates.io index
2806+
[UPDATING] crates.io index
2807+
[UPDATING] crates.io index
2808+
",
2809+
)
2810+
.run();
2811+
2812+
let p = project()
2813+
.file(
2814+
"Cargo.toml",
2815+
r#"
2816+
[package]
2817+
name = "foo"
2818+
version = "0.0.1"
2819+
authors = []
2820+
[dependencies]
2821+
delay = "0.0.2"
2822+
"#,
2823+
)
2824+
.file("src/main.rs", "fn main() {}")
2825+
.build();
2826+
2827+
p.cargo("check").with_status(0).run();
2828+
}

0 commit comments

Comments
 (0)