Skip to content

Commit 838e9c5

Browse files
committed
Auto merge of #41268 - mmatyas:test_on_device, r=alexcrichton
Run non-native tests on real device After #40733, I've made some hacks to the QEMU client-server tools to allow running the tests on a real device when cross compiling Rust. The address and port of the remote server can be set using an environment variable. I've made this mainly for local testing purposes, if you're interested in merging this, I'd clean it a bit more (eg. renaming the functions from `qemu-` to something else). I'm not asking for CI integration or adding ARM boards to the build system; it's just that I used these modifications and I was wondering if you'd find them useful too.
2 parents 222971f + b194def commit 838e9c5

File tree

4 files changed

+80
-29
lines changed

4 files changed

+80
-29
lines changed

src/bootstrap/check.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ fn find_tests(dir: &Path,
529529
}
530530
}
531531

532-
pub fn emulator_copy_libs(build: &Build, compiler: &Compiler, target: &str) {
532+
pub fn remote_copy_libs(build: &Build, compiler: &Compiler, target: &str) {
533533
if !build.remote_tested(target) {
534534
return
535535
}

src/bootstrap/step.rs

+18-18
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
307307
.dep(|s| s.name("libtest"))
308308
.dep(|s| s.name("tool-compiletest").target(s.host).stage(0))
309309
.dep(|s| s.name("test-helpers"))
310-
.dep(|s| s.name("emulator-copy-libs"))
310+
.dep(|s| s.name("remote-copy-libs"))
311311
.default(mode != "pretty") // pretty tests don't run everywhere
312312
.run(move |s| {
313313
check::compiletest(build, &s.compiler(), s.target, mode, dir)
@@ -346,7 +346,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
346346
.dep(|s| s.name("tool-compiletest").target(s.host).stage(0))
347347
.dep(|s| s.name("test-helpers"))
348348
.dep(|s| s.name("debugger-scripts"))
349-
.dep(|s| s.name("emulator-copy-libs"))
349+
.dep(|s| s.name("remote-copy-libs"))
350350
.run(move |s| check::compiletest(build, &s.compiler(), s.target,
351351
"debuginfo-gdb", "debuginfo"));
352352
let mut rule = rules.test("check-debuginfo", "src/test/debuginfo");
@@ -400,14 +400,14 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
400400
for (krate, path, _default) in krates("std") {
401401
rules.test(&krate.test_step, path)
402402
.dep(|s| s.name("libtest"))
403-
.dep(|s| s.name("emulator-copy-libs"))
403+
.dep(|s| s.name("remote-copy-libs"))
404404
.run(move |s| check::krate(build, &s.compiler(), s.target,
405405
Mode::Libstd, TestKind::Test,
406406
Some(&krate.name)));
407407
}
408408
rules.test("check-std-all", "path/to/nowhere")
409409
.dep(|s| s.name("libtest"))
410-
.dep(|s| s.name("emulator-copy-libs"))
410+
.dep(|s| s.name("remote-copy-libs"))
411411
.default(true)
412412
.run(move |s| check::krate(build, &s.compiler(), s.target,
413413
Mode::Libstd, TestKind::Test, None));
@@ -416,44 +416,44 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
416416
for (krate, path, _default) in krates("std") {
417417
rules.bench(&krate.bench_step, path)
418418
.dep(|s| s.name("libtest"))
419-
.dep(|s| s.name("emulator-copy-libs"))
419+
.dep(|s| s.name("remote-copy-libs"))
420420
.run(move |s| check::krate(build, &s.compiler(), s.target,
421421
Mode::Libstd, TestKind::Bench,
422422
Some(&krate.name)));
423423
}
424424
rules.bench("bench-std-all", "path/to/nowhere")
425425
.dep(|s| s.name("libtest"))
426-
.dep(|s| s.name("emulator-copy-libs"))
426+
.dep(|s| s.name("remote-copy-libs"))
427427
.default(true)
428428
.run(move |s| check::krate(build, &s.compiler(), s.target,
429429
Mode::Libstd, TestKind::Bench, None));
430430

431431
for (krate, path, _default) in krates("test") {
432432
rules.test(&krate.test_step, path)
433433
.dep(|s| s.name("libtest"))
434-
.dep(|s| s.name("emulator-copy-libs"))
434+
.dep(|s| s.name("remote-copy-libs"))
435435
.run(move |s| check::krate(build, &s.compiler(), s.target,
436436
Mode::Libtest, TestKind::Test,
437437
Some(&krate.name)));
438438
}
439439
rules.test("check-test-all", "path/to/nowhere")
440440
.dep(|s| s.name("libtest"))
441-
.dep(|s| s.name("emulator-copy-libs"))
441+
.dep(|s| s.name("remote-copy-libs"))
442442
.default(true)
443443
.run(move |s| check::krate(build, &s.compiler(), s.target,
444444
Mode::Libtest, TestKind::Test, None));
445445
for (krate, path, _default) in krates("rustc-main") {
446446
rules.test(&krate.test_step, path)
447447
.dep(|s| s.name("librustc"))
448-
.dep(|s| s.name("emulator-copy-libs"))
448+
.dep(|s| s.name("remote-copy-libs"))
449449
.host(true)
450450
.run(move |s| check::krate(build, &s.compiler(), s.target,
451451
Mode::Librustc, TestKind::Test,
452452
Some(&krate.name)));
453453
}
454454
rules.test("check-rustc-all", "path/to/nowhere")
455455
.dep(|s| s.name("librustc"))
456-
.dep(|s| s.name("emulator-copy-libs"))
456+
.dep(|s| s.name("remote-copy-libs"))
457457
.default(true)
458458
.host(true)
459459
.run(move |s| check::krate(build, &s.compiler(), s.target,
@@ -500,17 +500,17 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
500500
rules.build("openssl", "path/to/nowhere")
501501
.run(move |s| native::openssl(build, s.target));
502502

503-
// Some test suites are run inside emulators, and most of our test binaries
504-
// are linked dynamically which means we need to ship the standard library
505-
// and such to the emulator ahead of time. This step represents this and is
506-
// a dependency of all test suites.
503+
// Some test suites are run inside emulators or on remote devices, and most
504+
// of our test binaries are linked dynamically which means we need to ship
505+
// the standard library and such to the emulator ahead of time. This step
506+
// represents this and is a dependency of all test suites.
507507
//
508508
// Most of the time this step is a noop (the `check::emulator_copy_libs`
509509
// only does work if necessary). For some steps such as shipping data to
510510
// QEMU we have to build our own tools so we've got conditional dependencies
511-
// on those programs as well. Note that the QEMU client is built for the
512-
// build target (us) and the server is built for the target.
513-
rules.test("emulator-copy-libs", "path/to/nowhere")
511+
// on those programs as well. Note that the remote test client is built for
512+
// the build target (us) and the server is built for the target.
513+
rules.test("remote-copy-libs", "path/to/nowhere")
514514
.dep(|s| s.name("libtest"))
515515
.dep(move |s| {
516516
if build.remote_tested(s.target) {
@@ -526,7 +526,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
526526
Step::noop()
527527
}
528528
})
529-
.run(move |s| check::emulator_copy_libs(build, &s.compiler(), s.target));
529+
.run(move |s| check::remote_copy_libs(build, &s.compiler(), s.target));
530530

531531
rules.test("check-bootstrap", "src/bootstrap")
532532
.default(true)

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

+12-4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ use std::process::{Command, Stdio};
2525
use std::thread;
2626
use std::time::Duration;
2727

28+
const REMOTE_ADDR_ENV: &'static str = "TEST_DEVICE_ADDR";
29+
2830
macro_rules! t {
2931
($e:expr) => (match $e {
3032
Ok(e) => e,
@@ -56,7 +58,11 @@ fn spawn_emulator(target: &str,
5658
server: &Path,
5759
tmpdir: &Path,
5860
rootfs: Option<PathBuf>) {
59-
if target.contains("android") {
61+
let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or("127.0.0.1:12345".to_string());
62+
63+
if env::var(REMOTE_ADDR_ENV).is_ok() {
64+
println!("Connecting to remote device {} ...", device_address);
65+
} else if target.contains("android") {
6066
start_android_emulator(server);
6167
} else {
6268
let rootfs = rootfs.as_ref().expect("need rootfs on non-android");
@@ -66,7 +72,7 @@ fn spawn_emulator(target: &str,
6672
// Wait for the emulator to come online
6773
loop {
6874
let dur = Duration::from_millis(100);
69-
if let Ok(mut client) = TcpStream::connect("127.0.0.1:12345") {
75+
if let Ok(mut client) = TcpStream::connect(&device_address) {
7076
t!(client.set_read_timeout(Some(dur)));
7177
t!(client.set_write_timeout(Some(dur)));
7278
if client.write_all(b"ping").is_ok() {
@@ -162,7 +168,8 @@ fn start_qemu_emulator(rootfs: &Path, server: &Path, tmpdir: &Path) {
162168
}
163169

164170
fn push(path: &Path) {
165-
let client = t!(TcpStream::connect("127.0.0.1:12345"));
171+
let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or("127.0.0.1:12345".to_string());
172+
let client = t!(TcpStream::connect(device_address));
166173
let mut client = BufWriter::new(client);
167174
t!(client.write_all(b"push"));
168175
send(path, &mut client);
@@ -178,7 +185,8 @@ fn push(path: &Path) {
178185
}
179186

180187
fn run(files: String, args: Vec<String>) {
181-
let client = t!(TcpStream::connect("127.0.0.1:12345"));
188+
let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or("127.0.0.1:12345".to_string());
189+
let client = t!(TcpStream::connect(device_address));
182190
let mut client = BufWriter::new(client);
183191
t!(client.write_all(b"run "));
184192

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

+49-6
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
/// This is a small server which is intended to run inside of an emulator. This
12-
/// server pairs with the `remote-test-client` program in this repository. The
13-
/// `remote-test-client` connects to this server over a TCP socket and performs
14-
/// work such as:
11+
/// This is a small server which is intended to run inside of an emulator or
12+
/// on a remote test device. This server pairs with the `remote-test-client`
13+
/// program in this repository. The `remote-test-client` connects to this
14+
/// server over a TCP socket and performs work such as:
1515
///
1616
/// 1. Pushing shared libraries to the server
1717
/// 2. Running tests through the server
@@ -21,6 +21,7 @@
2121
/// basically custom format suiting our needs.
2222
2323
use std::cmp;
24+
use std::env;
2425
use std::fs::{self, File, Permissions};
2526
use std::io::prelude::*;
2627
use std::io::{self, BufReader};
@@ -42,12 +43,54 @@ macro_rules! t {
4243

4344
static TEST: AtomicUsize = ATOMIC_USIZE_INIT;
4445

46+
struct Config {
47+
pub remote: bool,
48+
pub verbose: bool,
49+
}
50+
51+
impl Config {
52+
pub fn default() -> Config {
53+
Config {
54+
remote: false,
55+
verbose: false,
56+
}
57+
}
58+
59+
pub fn parse_args() -> Config {
60+
let mut config = Config::default();
61+
62+
let args = env::args().skip(1);
63+
for argument in args {
64+
match &argument[..] {
65+
"remote" => {
66+
config.remote = true;
67+
},
68+
"verbose" | "-v" => {
69+
config.verbose = true;
70+
}
71+
arg => panic!("unknown argument: {}", arg),
72+
}
73+
}
74+
75+
config
76+
}
77+
}
78+
4579
fn main() {
4680
println!("starting test server");
81+
82+
let config = Config::parse_args();
83+
84+
let bind_addr = if cfg!(target_os = "android") || config.remote {
85+
"0.0.0.0:12345"
86+
} else {
87+
"10.0.2.15:12345"
88+
};
89+
4790
let (listener, work) = if cfg!(target_os = "android") {
48-
(t!(TcpListener::bind("0.0.0.0:12345")), "/data/tmp/work")
91+
(t!(TcpListener::bind(bind_addr)), "/data/tmp/work")
4992
} else {
50-
(t!(TcpListener::bind("10.0.2.15:12345")), "/tmp/work")
93+
(t!(TcpListener::bind(bind_addr)), "/tmp/work")
5194
};
5295
println!("listening!");
5396

0 commit comments

Comments
 (0)