| use std::path::{Path, PathBuf}; | |
| use std::process::Command; | |
| use std::{env, fs}; | |
| struct Test { | |
| repo: &'static str, | |
| name: &'static str, | |
| sha: &'static str, | |
| lock: Option<&'static str>, | |
| packages: &'static [&'static str], | |
| features: Option<&'static [&'static str]>, | |
| manifest_path: Option<&'static str>, | |
| /// `filters` are passed to libtest (i.e., after a `--` in the `cargo test` invocation). | |
| filters: &'static [&'static str], | |
| } | |
| const TEST_REPOS: &[Test] = &[ | |
| Test { | |
| name: "iron", | |
| repo: "https://github.com/iron/iron", | |
| sha: "cf056ea5e8052c1feea6141e40ab0306715a2c33", | |
| lock: None, | |
| packages: &[], | |
| features: None, | |
| manifest_path: None, | |
| filters: &[], | |
| }, | |
| Test { | |
| name: "ripgrep", | |
| repo: "https://github.com/BurntSushi/ripgrep", | |
| sha: "ced5b92aa93eb47e892bd2fd26ab454008721730", | |
| lock: None, | |
| packages: &[], | |
| features: None, | |
| manifest_path: None, | |
| filters: &[], | |
| }, | |
| Test { | |
| name: "tokei", | |
| repo: "https://github.com/XAMPPRocky/tokei", | |
| sha: "fdf3f8cb279a7aeac0696c87e5d8b0cd946e4f9e", | |
| lock: None, | |
| packages: &[], | |
| features: None, | |
| manifest_path: None, | |
| filters: &[], | |
| }, | |
| Test { | |
| name: "xsv", | |
| repo: "https://github.com/BurntSushi/xsv", | |
| sha: "3de6c04269a7d315f7e9864b9013451cd9580a08", | |
| lock: None, | |
| packages: &[], | |
| features: None, | |
| manifest_path: None, | |
| // Many tests here use quickcheck and some of them can fail randomly, so only run deterministic tests. | |
| filters: &[ | |
| "test_flatten::", | |
| "test_fmt::", | |
| "test_headers::", | |
| "test_index::", | |
| "test_join::", | |
| "test_partition::", | |
| "test_search::", | |
| "test_select::", | |
| "test_slice::", | |
| "test_split::", | |
| "test_stats::", | |
| "test_table::", | |
| ], | |
| }, | |
| Test { | |
| name: "servo", | |
| repo: "https://github.com/servo/servo", | |
| sha: "785a344e32db58d4e631fd3cae17fd1f29a721ab", | |
| lock: None, | |
| // Only test Stylo a.k.a. Quantum CSS, the parts of Servo going into Firefox. | |
| // This takes much less time to build than all of Servo and supports stable Rust. | |
| packages: &["selectors"], | |
| features: None, | |
| manifest_path: None, | |
| filters: &[], | |
| }, | |
| Test { | |
| name: "diesel", | |
| repo: "https://github.com/diesel-rs/diesel", | |
| sha: "3db7c17c5b069656ed22750e84d6498c8ab5b81d", | |
| lock: None, | |
| packages: &[], | |
| // Test the embedded sqlite variant of diesel | |
| // This does not require any dependency to be present, | |
| // sqlite will be compiled as part of the build process | |
| features: Some(&["sqlite", "libsqlite3-sys/bundled"]), | |
| // We are only interested in testing diesel itself | |
| // not any other crate present in the diesel workspace | |
| // (This is required to set the feature flags above) | |
| manifest_path: Some("diesel/Cargo.toml"), | |
| filters: &[], | |
| }, | |
| ]; | |
| fn main() { | |
| let args = env::args().collect::<Vec<_>>(); | |
| let cargo = &args[1]; | |
| let out_dir = Path::new(&args[2]); | |
| let cargo = &Path::new(cargo); | |
| for test in TEST_REPOS.iter().rev() { | |
| if args[3..].is_empty() || args[3..].iter().any(|s| s.contains(test.name)) { | |
| test_repo(cargo, out_dir, test); | |
| } | |
| } | |
| } | |
| fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) { | |
| println!("testing {}", test.repo); | |
| let dir = clone_repo(test, out_dir); | |
| if let Some(lockfile) = test.lock { | |
| fs::write(&dir.join("Cargo.lock"), lockfile).unwrap(); | |
| } | |
| if !run_cargo_test(cargo, &dir, test.packages, test.features, test.manifest_path, test.filters) | |
| { | |
| panic!("tests failed for {}", test.repo); | |
| } | |
| } | |
| fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf { | |
| let out_dir = out_dir.join(test.name); | |
| if !out_dir.join(".git").is_dir() { | |
| let status = Command::new("git").arg("init").arg(&out_dir).status().unwrap(); | |
| assert!(status.success()); | |
| } | |
| // Try progressively deeper fetch depths to find the commit | |
| let mut found = false; | |
| for depth in &[0, 1, 10, 100, 1000, 100000] { | |
| if *depth > 0 { | |
| let status = Command::new("git") | |
| .arg("fetch") | |
| .arg(test.repo) | |
| .arg(test.sha) | |
| .arg(&format!("--depth={}", depth)) | |
| .current_dir(&out_dir) | |
| .status() | |
| .unwrap(); | |
| assert!(status.success()); | |
| } | |
| let status = Command::new("git") | |
| .arg("reset") | |
| .arg(test.sha) | |
| .arg("--hard") | |
| .current_dir(&out_dir) | |
| .status() | |
| .unwrap(); | |
| if status.success() { | |
| found = true; | |
| break; | |
| } | |
| } | |
| if !found { | |
| panic!("unable to find commit {}", test.sha) | |
| } | |
| let status = | |
| Command::new("git").arg("clean").arg("-fdx").current_dir(&out_dir).status().unwrap(); | |
| assert!(status.success()); | |
| out_dir | |
| } | |
| fn run_cargo_test( | |
| cargo_path: &Path, | |
| crate_path: &Path, | |
| packages: &[&str], | |
| features: Option<&[&str]>, | |
| manifest_path: Option<&str>, | |
| filters: &[&str], | |
| ) -> bool { | |
| let mut command = Command::new(cargo_path); | |
| command.arg("test"); | |
| if let Some(path) = manifest_path { | |
| command.arg(format!("--manifest-path={}", path)); | |
| } | |
| if let Some(features) = features { | |
| command.arg("--no-default-features"); | |
| for feature in features { | |
| command.arg(format!("--features={}", feature)); | |
| } | |
| } | |
| for name in packages { | |
| command.arg("-p").arg(name); | |
| } | |
| command.arg("--"); | |
| command.args(filters); | |
| let status = command | |
| // `xsv` locates binaries relative to `current_exe()` | |
| // which assumes Cargo legacy build-dir layout. | |
| // | |
| // See failure logs: | |
| // https://triage.rust-lang.org/gha-logs/rust-lang/rust/90658568103 | |
| // | |
| // FIXME(weihanglo): replace xsv to something else with similar portfolio. | |
| .env("__CARGO_TEMPORARY_BUILD_DIR_NEW_LAYOUT_OPT_OUT", "1") | |
| // Disable rust-lang/cargo's cross-compile tests | |
| .env("CFG_DISABLE_CROSS_TESTS", "1") | |
| // Relax #![deny(warnings)] in some crates | |
| .env("RUSTFLAGS", "--cap-lints warn") | |
| // servo tries to use 'lld-link.exe' on windows, but we don't | |
| // have lld on our PATH in CI. Override it to use 'link.exe' | |
| .env("CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER", "link.exe") | |
| .env("CARGO_TARGET_I686_PC_WINDOWS_MSVC_LINKER", "link.exe") | |
| .current_dir(crate_path) | |
| .status() | |
| .unwrap(); | |
| status.success() | |
| } |