Skip to content

Commit 7f09588

Browse files
authored
Rollup merge of #147952 - ferrocene:pvdrz/remote-test-client-timeout, r=Enselic,jieyouxu
Add a timeout to the `remote-test-client` connection Currently, the `remote-test-client` doesn't have a timeout when connecting to the `remote-test-server`. This means that running tests using it can hang indefinitely which causes issues when running tests on CI, for example. This PR now sets a default timeout of 5 minutes, meaning that if, for example, `TEST_DEVICE_ADDR=<IP:PORT> ./x test --target riscv64gc-unknown-linux-gnu tests/ui` is run and the `remote-test-server` is not reachable by the client, the client will panic after the timeout is reached. Additionally, the `TEST_DEVICE_CONNECT_TIMEOUT` env variable can be used to set up the timeout to any value (in seconds). This PR also wires up a test step for `remote-test-client`, which didn't previously have tool tests run in CI.
2 parents fc61266 + bd14144 commit 7f09588

File tree

7 files changed

+148
-2
lines changed

7 files changed

+148
-2
lines changed

Cargo.lock

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,21 @@ dependencies = [
229229
"winnow 0.7.13",
230230
]
231231

232+
[[package]]
233+
name = "assert_cmd"
234+
version = "2.1.1"
235+
source = "registry+https://github.com/rust-lang/crates.io-index"
236+
checksum = "bcbb6924530aa9e0432442af08bbcafdad182db80d2e560da42a6d442535bf85"
237+
dependencies = [
238+
"anstyle",
239+
"bstr",
240+
"libc",
241+
"predicates",
242+
"predicates-core",
243+
"predicates-tree",
244+
"wait-timeout",
245+
]
246+
232247
[[package]]
233248
name = "autocfg"
234249
version = "1.5.0"
@@ -1128,6 +1143,12 @@ version = "0.1.13"
11281143
source = "registry+https://github.com/rust-lang/crates.io-index"
11291144
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
11301145

1146+
[[package]]
1147+
name = "difflib"
1148+
version = "0.4.0"
1149+
source = "registry+https://github.com/rust-lang/crates.io-index"
1150+
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
1151+
11311152
[[package]]
11321153
name = "digest"
11331154
version = "0.10.7"
@@ -2949,6 +2970,33 @@ version = "0.1.1"
29492970
source = "registry+https://github.com/rust-lang/crates.io-index"
29502971
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
29512972

2973+
[[package]]
2974+
name = "predicates"
2975+
version = "3.1.3"
2976+
source = "registry+https://github.com/rust-lang/crates.io-index"
2977+
checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573"
2978+
dependencies = [
2979+
"anstyle",
2980+
"difflib",
2981+
"predicates-core",
2982+
]
2983+
2984+
[[package]]
2985+
name = "predicates-core"
2986+
version = "1.0.9"
2987+
source = "registry+https://github.com/rust-lang/crates.io-index"
2988+
checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa"
2989+
2990+
[[package]]
2991+
name = "predicates-tree"
2992+
version = "1.0.12"
2993+
source = "registry+https://github.com/rust-lang/crates.io-index"
2994+
checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c"
2995+
dependencies = [
2996+
"predicates-core",
2997+
"termtree",
2998+
]
2999+
29523000
[[package]]
29533001
name = "prettydiff"
29543002
version = "0.7.0"
@@ -3229,6 +3277,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
32293277
[[package]]
32303278
name = "remote-test-client"
32313279
version = "0.1.0"
3280+
dependencies = [
3281+
"assert_cmd",
3282+
]
32323283

32333284
[[package]]
32343285
name = "remote-test-server"
@@ -5425,6 +5476,12 @@ dependencies = [
54255476
"windows-sys 0.60.2",
54265477
]
54275478

5479+
[[package]]
5480+
name = "termtree"
5481+
version = "0.5.1"
5482+
source = "registry+https://github.com/rust-lang/crates.io-index"
5483+
checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683"
5484+
54285485
[[package]]
54295486
name = "test-float-parse"
54305487
version = "0.1.0"
@@ -6043,6 +6100,15 @@ version = "0.9.5"
60436100
source = "registry+https://github.com/rust-lang/crates.io-index"
60446101
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
60456102

6103+
[[package]]
6104+
name = "wait-timeout"
6105+
version = "0.2.1"
6106+
source = "registry+https://github.com/rust-lang/crates.io-index"
6107+
checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11"
6108+
dependencies = [
6109+
"libc",
6110+
]
6111+
60466112
[[package]]
60476113
name = "walkdir"
60486114
version = "2.5.0"

src/bootstrap/src/core/build_steps/test.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3986,3 +3986,40 @@ impl Step for CollectLicenseMetadata {
39863986
dest
39873987
}
39883988
}
3989+
3990+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3991+
pub struct RemoteTestClientTests {
3992+
host: TargetSelection,
3993+
}
3994+
3995+
impl Step for RemoteTestClientTests {
3996+
type Output = ();
3997+
const IS_HOST: bool = true;
3998+
const DEFAULT: bool = true;
3999+
4000+
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
4001+
run.path("src/tools/remote-test-client")
4002+
}
4003+
4004+
fn make_run(run: RunConfig<'_>) {
4005+
run.builder.ensure(Self { host: run.target });
4006+
}
4007+
4008+
fn run(self, builder: &Builder<'_>) {
4009+
let bootstrap_host = builder.config.host_target;
4010+
let compiler = builder.compiler(0, bootstrap_host);
4011+
4012+
let cargo = tool::prepare_tool_cargo(
4013+
builder,
4014+
compiler,
4015+
Mode::ToolBootstrap,
4016+
bootstrap_host,
4017+
Kind::Test,
4018+
"src/tools/remote-test-client",
4019+
SourceType::InTree,
4020+
&[],
4021+
);
4022+
4023+
run_cargo_test(cargo, &[], &[], "remote-test-client", bootstrap_host, builder);
4024+
}
4025+
}

src/bootstrap/src/core/builder/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,7 @@ impl<'a> Builder<'a> {
891891
test::CrateRustdoc,
892892
test::CrateRustdocJsonTypes,
893893
test::CrateBootstrap,
894+
test::RemoteTestClientTests,
894895
test::Linkcheck,
895896
test::TierCheck,
896897
test::Cargotest,

src/doc/rustc-dev-guide/src/tests/running.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,10 @@ Tests are built on the machine running `x` not on the remote machine. Tests
319319
which fail to build unexpectedly (or `ui` tests producing incorrect build
320320
output) may fail without ever running on the remote machine.
321321

322+
There is a default timeout of 30 minutes in case the `remote-test-server`
323+
cannot be reached by the `x` command. This timeout can be modified by using the
324+
`TEST_DEVICE_TIMEOUT_SECONDS` environment variable.
325+
322326
## Testing on emulators
323327

324328
Some platforms are tested via an emulator for architectures that aren't readily

src/tools/remote-test-client/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
7+
assert_cmd = "2"

src/tools/remote-test-client/src/main.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@ use std::io::{self, BufWriter};
1111
use std::net::TcpStream;
1212
use std::path::{Path, PathBuf};
1313
use std::process::{Command, Stdio};
14-
use std::time::Duration;
14+
use std::time::{Duration, Instant};
1515
use std::{env, thread};
1616

1717
const REMOTE_ADDR_ENV: &str = "TEST_DEVICE_ADDR";
1818
const DEFAULT_ADDR: &str = "127.0.0.1:12345";
1919

20+
const CONNECT_TIMEOUT_ENV: &str = "TEST_DEVICE_CONNECT_TIMEOUT_SECONDS";
21+
/// The default timeout is high to not break slow CI or slow device starts.
22+
const DEFAULT_CONNECT_TIMEOUT: Duration = Duration::from_mins(30);
23+
2024
macro_rules! t {
2125
($e:expr) => {
2226
match $e {
@@ -56,6 +60,17 @@ fn main() {
5660
}
5761
}
5862

63+
fn connect_timeout() -> Duration {
64+
match env::var(CONNECT_TIMEOUT_ENV).ok() {
65+
Some(timeout) => timeout.parse().map(Duration::from_secs).unwrap_or_else(|e| {
66+
panic!(
67+
"error: parsing `{CONNECT_TIMEOUT_ENV}` value \"{timeout}\" as seconds failed: {e}"
68+
)
69+
}),
70+
None => DEFAULT_CONNECT_TIMEOUT,
71+
}
72+
}
73+
5974
fn spawn_emulator(target: &str, server: &Path, tmpdir: &Path, rootfs: Option<PathBuf>) {
6075
let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or(DEFAULT_ADDR.to_string());
6176

@@ -69,20 +84,28 @@ fn spawn_emulator(target: &str, server: &Path, tmpdir: &Path, rootfs: Option<Pat
6984
}
7085

7186
// Wait for the emulator to come online
72-
loop {
87+
let timeout = connect_timeout();
88+
let mut successful_read = false;
89+
let start_time = Instant::now();
90+
while start_time.elapsed() < timeout {
7391
let dur = Duration::from_millis(2000);
7492
if let Ok(mut client) = TcpStream::connect(&device_address) {
7593
t!(client.set_read_timeout(Some(dur)));
7694
t!(client.set_write_timeout(Some(dur)));
7795
if client.write_all(b"ping").is_ok() {
7896
let mut b = [0; 4];
7997
if client.read_exact(&mut b).is_ok() {
98+
successful_read = true;
8099
break;
81100
}
82101
}
83102
}
84103
thread::sleep(dur);
85104
}
105+
106+
if !successful_read {
107+
panic!("Gave up trying to connect to test device at {device_address} after {timeout:?}");
108+
}
86109
}
87110

88111
fn start_android_emulator(server: &Path) {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#[test]
2+
fn test_timeout() {
3+
let mut cmd = assert_cmd::cargo::cargo_bin_cmd!();
4+
cmd.env("TEST_DEVICE_CONNECT_TIMEOUT_SECONDS", "1");
5+
cmd.env("TEST_DEVICE_ADDR", "0.0.0.0:6969");
6+
cmd.args(["spawn-emulator", "riscv64-unknown-linux-gnu", "./"]);
7+
cmd.arg(std::env::temp_dir());
8+
9+
let assert = cmd.assert().failure();
10+
let output = assert.get_output();
11+
12+
let stderr = String::from_utf8(output.stderr.clone()).unwrap();
13+
assert!(stderr.contains("Gave up trying to connect to test device"));
14+
}

0 commit comments

Comments
 (0)