Skip to content

Commit 16afe1a

Browse files
committed
Add some more publish timeout tests
1 parent c4267f3 commit 16afe1a

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 {
@@ -264,6 +274,7 @@ impl RegistryBuilder {
264274
token.clone(),
265275
self.auth_required,
266276
self.custom_responders,
277+
self.delayed_index_update,
267278
);
268279
let index_url = if self.http_index {
269280
server.index_url()
@@ -589,6 +600,7 @@ pub struct HttpServer {
589600
token: Token,
590601
auth_required: bool,
591602
custom_responders: HashMap<&'static str, Box<dyn Send + Fn(&Request, &HttpServer) -> Response>>,
603+
delayed_index_update: usize,
592604
}
593605

594606
/// A helper struct that collects the arguments for [HttpServer::check_authorized].
@@ -610,6 +622,7 @@ impl HttpServer {
610622
&'static str,
611623
Box<dyn Send + Fn(&Request, &HttpServer) -> Response>,
612624
>,
625+
delayed_index_update: usize,
613626
) -> HttpServerHandle {
614627
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
615628
let addr = listener.local_addr().unwrap();
@@ -621,6 +634,7 @@ impl HttpServer {
621634
token,
622635
auth_required,
623636
custom_responders: api_responders,
637+
delayed_index_update,
624638
};
625639
let handle = Some(thread::spawn(move || server.start()));
626640
HttpServerHandle { addr, handle }
@@ -1030,49 +1044,23 @@ impl HttpServer {
10301044
return self.unauthorized(req);
10311045
}
10321046

1033-
// Write the `.crate`
10341047
let dst = self
10351048
.dl_path
10361049
.join(&new_crate.name)
10371050
.join(&new_crate.vers)
10381051
.join("download");
1039-
t!(fs::create_dir_all(dst.parent().unwrap()));
1040-
t!(fs::write(&dst, file));
1041-
1042-
let deps = new_crate
1043-
.deps
1044-
.iter()
1045-
.map(|dep| {
1046-
let (name, package) = match &dep.explicit_name_in_toml {
1047-
Some(explicit) => (explicit.to_string(), Some(dep.name.to_string())),
1048-
None => (dep.name.to_string(), None),
1049-
};
1050-
serde_json::json!({
1051-
"name": name,
1052-
"req": dep.version_req,
1053-
"features": dep.features,
1054-
"default_features": true,
1055-
"target": dep.target,
1056-
"optional": dep.optional,
1057-
"kind": dep.kind,
1058-
"registry": dep.registry,
1059-
"package": package,
1060-
})
1061-
})
1062-
.collect::<Vec<_>>();
1063-
1064-
let line = create_index_line(
1065-
serde_json::json!(new_crate.name),
1066-
&new_crate.vers,
1067-
deps,
1068-
&file_cksum,
1069-
new_crate.features,
1070-
false,
1071-
new_crate.links,
1072-
None,
1073-
);
10741052

1075-
write_to_index(&self.registry_path, &new_crate.name, line, false);
1053+
if self.delayed_index_update == 0 {
1054+
save_new_crate(dst, new_crate, file, file_cksum, &self.registry_path);
1055+
} else {
1056+
let delayed_index_update = self.delayed_index_update;
1057+
let registry_path = self.registry_path.clone();
1058+
let file = Vec::from(file);
1059+
thread::spawn(move || {
1060+
thread::sleep(std::time::Duration::new(delayed_index_update as u64, 0));
1061+
save_new_crate(dst, new_crate, &file, file_cksum, &registry_path);
1062+
});
1063+
}
10761064

10771065
self.ok(&req)
10781066
} else {
@@ -1085,6 +1073,53 @@ impl HttpServer {
10851073
}
10861074
}
10871075

1076+
fn save_new_crate(
1077+
dst: PathBuf,
1078+
new_crate: crates_io::NewCrate,
1079+
file: &[u8],
1080+
file_cksum: String,
1081+
registry_path: &Path,
1082+
) {
1083+
// Write the `.crate`
1084+
t!(fs::create_dir_all(dst.parent().unwrap()));
1085+
t!(fs::write(&dst, file));
1086+
1087+
let deps = new_crate
1088+
.deps
1089+
.iter()
1090+
.map(|dep| {
1091+
let (name, package) = match &dep.explicit_name_in_toml {
1092+
Some(explicit) => (explicit.to_string(), Some(dep.name.to_string())),
1093+
None => (dep.name.to_string(), None),
1094+
};
1095+
serde_json::json!({
1096+
"name": name,
1097+
"req": dep.version_req,
1098+
"features": dep.features,
1099+
"default_features": true,
1100+
"target": dep.target,
1101+
"optional": dep.optional,
1102+
"kind": dep.kind,
1103+
"registry": dep.registry,
1104+
"package": package,
1105+
})
1106+
})
1107+
.collect::<Vec<_>>();
1108+
1109+
let line = create_index_line(
1110+
serde_json::json!(new_crate.name),
1111+
&new_crate.vers,
1112+
deps,
1113+
&file_cksum,
1114+
new_crate.features,
1115+
false,
1116+
new_crate.links,
1117+
None,
1118+
);
1119+
1120+
write_to_index(registry_path, &new_crate.name, line, false);
1121+
}
1122+
10881123
impl Package {
10891124
/// Creates a new package builder.
10901125
/// 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
@@ -2770,3 +2770,127 @@ See [..]
27702770
)
27712771
.run();
27722772
}
2773+
2774+
#[cargo_test]
2775+
fn timeout_waiting_for_publish() {
2776+
// Publish doesn't happen within the timeout window.
2777+
let registry = registry::RegistryBuilder::new()
2778+
.http_api()
2779+
.delayed_index_update(20)
2780+
.build();
2781+
2782+
let p = project()
2783+
.file(
2784+
"Cargo.toml",
2785+
r#"
2786+
[package]
2787+
name = "delay"
2788+
version = "0.0.1"
2789+
authors = []
2790+
license = "MIT"
2791+
description = "foo"
2792+
"#,
2793+
)
2794+
.file("src/lib.rs", "")
2795+
.file(
2796+
".cargo/config.toml",
2797+
r#"
2798+
[publish]
2799+
timeout = 2
2800+
"#,
2801+
)
2802+
.build();
2803+
2804+
p.cargo("publish --no-verify -Zpublish-timeout")
2805+
.replace_crates_io(registry.index_url())
2806+
.masquerade_as_nightly_cargo(&["publish-timeout"])
2807+
.with_status(0)
2808+
// There may be a variable number of "Updating crates.io index" at the
2809+
// end, which is timing-dependent.
2810+
.with_stderr_contains(
2811+
"\
2812+
[UPDATING] crates.io index
2813+
[WARNING] manifest has no documentation, [..]
2814+
See [..]
2815+
[PACKAGING] delay v0.0.1 ([CWD])
2816+
[PACKAGED] [..] files, [..] ([..] compressed)
2817+
[UPLOADING] delay v0.0.1 ([CWD])
2818+
[UPDATING] crates.io index
2819+
[WAITING] on `delay` to propagate to crates.io index (ctrl-c to wait asynchronously)
2820+
",
2821+
)
2822+
.with_stderr_contains("warning: timed out waiting for `delay` to be in crates.io index")
2823+
.run();
2824+
}
2825+
2826+
#[cargo_test]
2827+
fn wait_for_git_publish() {
2828+
// Slow publish to an index with a git index.
2829+
let registry = registry::RegistryBuilder::new()
2830+
.http_api()
2831+
.delayed_index_update(5)
2832+
.build();
2833+
2834+
// Publish an earlier version
2835+
Package::new("delay", "0.0.1")
2836+
.file("src/lib.rs", "")
2837+
.publish();
2838+
2839+
let p = project()
2840+
.file(
2841+
"Cargo.toml",
2842+
r#"
2843+
[package]
2844+
name = "delay"
2845+
version = "0.0.2"
2846+
authors = []
2847+
license = "MIT"
2848+
description = "foo"
2849+
"#,
2850+
)
2851+
.file("src/lib.rs", "")
2852+
.build();
2853+
2854+
p.cargo("publish --no-verify")
2855+
.replace_crates_io(registry.index_url())
2856+
.with_status(0)
2857+
.with_stderr_contains(
2858+
"\
2859+
[UPDATING] crates.io index
2860+
[WARNING] manifest has no documentation, [..]
2861+
See [..]
2862+
[PACKAGING] delay v0.0.2 ([CWD])
2863+
[PACKAGED] [..] files, [..] ([..] compressed)
2864+
[UPLOADING] delay v0.0.2 ([CWD])
2865+
[UPDATING] crates.io index
2866+
[WAITING] on `delay` to propagate to crates.io index (ctrl-c to wait asynchronously)
2867+
",
2868+
)
2869+
// The exact number of updates is timing dependent. This just checks
2870+
// that at least a few show up.
2871+
.with_stderr_contains(
2872+
"\
2873+
[UPDATING] crates.io index
2874+
[UPDATING] crates.io index
2875+
[UPDATING] crates.io index
2876+
",
2877+
)
2878+
.run();
2879+
2880+
let p = project()
2881+
.file(
2882+
"Cargo.toml",
2883+
r#"
2884+
[package]
2885+
name = "foo"
2886+
version = "0.0.1"
2887+
authors = []
2888+
[dependencies]
2889+
delay = "0.0.2"
2890+
"#,
2891+
)
2892+
.file("src/main.rs", "fn main() {}")
2893+
.build();
2894+
2895+
p.cargo("check").with_status(0).run();
2896+
}

0 commit comments

Comments
 (0)