1 //! cargo_bazel integration tests that run Cargo to test generating metadata.
2
3 extern crate cargo_bazel;
4 extern crate serde_json;
5 extern crate tempfile;
6
7 use anyhow::{ensure, Context, Result};
8 use cargo_bazel::cli::{splice, SpliceOptions};
9 use serde_json::{json, Value};
10 use std::collections::HashMap;
11 use std::env;
12 use std::fs;
13 use std::path::PathBuf;
14
should_skip_test() -> bool15 fn should_skip_test() -> bool {
16 // All test cases require network access to build pull crate metadata
17 // so that we can actually run `cargo tree`. However, RBE (and perhaps
18 // other environments) disallow or don't support this. In those cases,
19 // we just skip this test case.
20 use std::net::ToSocketAddrs;
21 if "github.com:443".to_socket_addrs().is_err() {
22 eprintln!("This test case requires network access.");
23 true
24 } else {
25 false
26 }
27 }
28
setup_cargo_env() -> Result<(PathBuf, PathBuf)>29 fn setup_cargo_env() -> Result<(PathBuf, PathBuf)> {
30 let cargo = std::fs::canonicalize(PathBuf::from(
31 env::var("CARGO").context("CARGO environment variable must be set.")?,
32 ))
33 .unwrap();
34 let rustc = std::fs::canonicalize(PathBuf::from(
35 env::var("RUSTC").context("RUSTC environment variable must be set.")?,
36 ))
37 .unwrap();
38 ensure!(cargo.exists());
39 ensure!(rustc.exists());
40 // If $RUSTC is a relative path it can cause issues with
41 // `cargo_metadata::MetadataCommand`. Just to be on the safe side, we make
42 // both of these env variables absolute paths.
43 if cargo != PathBuf::from(env::var("CARGO").unwrap()) {
44 env::set_var("CARGO", cargo.as_os_str());
45 }
46 if rustc != PathBuf::from(env::var("RUSTC").unwrap()) {
47 env::set_var("RUSTC", rustc.as_os_str());
48 }
49
50 let cargo_home = PathBuf::from(
51 env::var("TEST_TMPDIR").context("TEST_TMPDIR environment variable must be set.")?,
52 )
53 .join("cargo_home");
54 env::set_var("CARGO_HOME", cargo_home.as_os_str());
55 fs::create_dir_all(&cargo_home)?;
56
57 println!("Environment:");
58 println!("\tRUSTC={}", rustc.display());
59 println!("\tCARGO={}", cargo.display());
60 println!("\tCARGO_HOME={}", cargo_home.display());
61
62 Ok((cargo, rustc))
63 }
64
run(repository_name: &str, manifests: HashMap<String, String>, lockfile: &str) -> Value65 fn run(repository_name: &str, manifests: HashMap<String, String>, lockfile: &str) -> Value {
66 let (cargo, rustc) = setup_cargo_env().unwrap();
67
68 let scratch = tempfile::tempdir().unwrap();
69 let runfiles = runfiles::Runfiles::create().unwrap();
70
71 let splicing_manifest = scratch.path().join("splicing_manifest.json");
72 fs::write(
73 &splicing_manifest,
74 serde_json::to_string(&json!({
75 "manifests": manifests,
76 "direct_packages": {},
77 "resolver_version": "2"
78 }))
79 .unwrap(),
80 )
81 .unwrap();
82
83 let config = scratch.path().join("config.json");
84 fs::write(
85 &config,
86 serde_json::to_string(&json!({
87 "generate_binaries": false,
88 "generate_build_scripts": false,
89 "rendering": {
90 "repository_name": repository_name,
91 "regen_command": "//crate_universe:cargo_integration_test"
92 },
93 "supported_platform_triples": [
94 "wasm32-unknown-unknown",
95 "x86_64-apple-darwin",
96 "x86_64-pc-windows-msvc",
97 "x86_64-unknown-linux-gnu",
98 ]
99 }))
100 .unwrap(),
101 )
102 .unwrap();
103
104 splice(SpliceOptions {
105 splicing_manifest,
106 cargo_lockfile: Some(runfiles::rlocation!(runfiles, lockfile)),
107 repin: None,
108 workspace_dir: None,
109 output_dir: scratch.path().join("out"),
110 dry_run: false,
111 cargo_config: None,
112 config,
113 cargo,
114 rustc,
115 })
116 .unwrap();
117
118 let metadata = serde_json::from_str::<Value>(
119 &fs::read_to_string(scratch.path().join("out").join("metadata.json")).unwrap(),
120 )
121 .unwrap();
122
123 metadata
124 }
125
126 // See crate_universe/test_data/metadata/target_features/Cargo.toml for input.
127 #[test]
feature_generator()128 fn feature_generator() {
129 if should_skip_test() {
130 eprintln!("Skipping!");
131 return;
132 }
133
134 let r = runfiles::Runfiles::create().unwrap();
135 let metadata = run(
136 "target_feature_test",
137 HashMap::from([(
138 runfiles::rlocation!(
139 r,
140 "rules_rust/crate_universe/test_data/metadata/target_features/Cargo.toml"
141 )
142 .to_string_lossy()
143 .to_string(),
144 "//:test_input".to_string(),
145 )]),
146 "rules_rust/crate_universe/test_data/metadata/target_features/Cargo.lock",
147 );
148
149 assert_eq!(
150 metadata["metadata"]["cargo-bazel"]["tree_metadata"]["wgpu-hal 0.14.1"],
151 json!({
152 "common": {
153 "deps": [
154 "arrayvec 0.7.2",
155 "bitflags 1.3.2",
156 "fxhash 0.2.1",
157 "log 0.4.17",
158 "naga 0.10.0",
159 "parking_lot 0.12.1",
160 "profiling 1.0.7",
161 "raw-window-handle 0.5.0",
162 "thiserror 1.0.37",
163 "wgpu-types 0.14.1",
164 ],
165 "features": [
166 "default",
167 ],
168 },
169 "selects": {
170 "x86_64-apple-darwin": {
171 "deps": [
172 "block 0.1.6",
173 "core-graphics-types 0.1.1",
174 "foreign-types 0.3.2",
175 "metal 0.24.0",
176 "objc 0.2.7",
177 ],
178 "features": [
179 "block",
180 "foreign-types",
181 "metal",
182 ],
183 },
184 "x86_64-pc-windows-msvc": {
185 "deps": [
186 "ash 0.37.1+1.3.235",
187 "bit-set 0.5.3",
188 "d3d12 0.5.0",
189 "gpu-alloc 0.5.3",
190 "gpu-descriptor 0.2.3",
191 "libloading 0.7.4",
192 "range-alloc 0.1.2",
193 "renderdoc-sys 0.7.1",
194 "smallvec 1.10.0",
195 "winapi 0.3.9",
196 ],
197 "features": [
198 "ash",
199 "bit-set",
200 "dx11",
201 "dx12",
202 "gpu-alloc",
203 "gpu-descriptor",
204 "libloading",
205 "native",
206 "range-alloc",
207 "renderdoc",
208 "renderdoc-sys",
209 "smallvec",
210 "vulkan",
211 ],
212 },
213 "x86_64-unknown-linux-gnu": {
214 "deps": [
215 "ash 0.37.1+1.3.235",
216 "glow 0.11.2",
217 "gpu-alloc 0.5.3",
218 "gpu-descriptor 0.2.3",
219 "khronos-egl 4.1.0",
220 "libloading 0.7.4",
221 "renderdoc-sys 0.7.1",
222 "smallvec 1.10.0",
223 ],
224 "features": [
225 "ash",
226 "egl",
227 "gles",
228 "glow",
229 "gpu-alloc",
230 "gpu-descriptor",
231 "libloading",
232 "renderdoc",
233 "renderdoc-sys",
234 "smallvec",
235 "vulkan",
236 ],
237 },
238 },
239 })
240 );
241 }
242
243 // See crate_universe/test_data/metadata/target_cfg_features/Cargo.toml for input.
244 #[test]
feature_generator_cfg_features()245 fn feature_generator_cfg_features() {
246 if should_skip_test() {
247 eprintln!("Skipping!");
248 return;
249 }
250
251 let r = runfiles::Runfiles::create().unwrap();
252 let metadata = run(
253 "target_cfg_features_test",
254 HashMap::from([(
255 runfiles::rlocation!(
256 r,
257 "rules_rust/crate_universe/test_data/metadata/target_cfg_features/Cargo.toml"
258 )
259 .to_string_lossy()
260 .to_string(),
261 "//:test_input".to_string(),
262 )]),
263 "rules_rust/crate_universe/test_data/metadata/target_cfg_features/Cargo.lock",
264 );
265
266 assert_eq!(
267 metadata["metadata"]["cargo-bazel"]["tree_metadata"],
268 json!({
269 "autocfg 1.1.0": {
270 "selects": {},
271 },
272 "pin-project-lite 0.2.9": {
273 "selects": {},
274 },
275 "target_cfg_features 0.1.0": {
276 "common": {
277 "deps": [
278 "tokio 1.25.0",
279 ],
280 },
281 "selects": {},
282 },
283 "tokio 1.25.0": {
284 "common": {
285 "deps": [
286 "autocfg 1.1.0",
287 "pin-project-lite 0.2.9",
288 ],
289 "features": [
290 "default",
291 ],
292 },
293 // Note: "x86_64-pc-windows-msvc" is *not* here, despite
294 // being included in `supported_platform_triples` above!
295 "selects": {
296 "x86_64-apple-darwin": {
297 "features": [
298 "fs",
299 ],
300 },
301 "x86_64-unknown-linux-gnu": {
302 "features": [
303 "fs",
304 ],
305 },
306 },
307 },
308 })
309 );
310 }
311
312 #[test]
feature_generator_workspace()313 fn feature_generator_workspace() {
314 if should_skip_test() {
315 eprintln!("Skipping!");
316 return;
317 }
318
319 let r = runfiles::Runfiles::create().unwrap();
320 let metadata = run(
321 "workspace_test",
322 HashMap::from([
323 (
324 runfiles::rlocation!(
325 r,
326 "rules_rust/crate_universe/test_data/metadata/workspace/Cargo.toml"
327 )
328 .to_string_lossy()
329 .to_string(),
330 "//:test_input".to_string(),
331 ),
332 (
333 runfiles::rlocation!(
334 r,
335 "rules_rust/crate_universe/test_data/metadata/workspace/child/Cargo.toml"
336 )
337 .to_string_lossy()
338 .to_string(),
339 "//crate_universe:test_data/metadata/workspace/child/Cargo.toml".to_string(),
340 ),
341 ]),
342 "rules_rust/crate_universe/test_data/metadata/workspace/Cargo.lock",
343 );
344
345 assert!(!metadata["metadata"]["cargo-bazel"]["tree_metadata"]["wgpu 0.14.0"].is_null());
346 }
347
348 #[test]
feature_generator_crate_combined_features()349 fn feature_generator_crate_combined_features() {
350 if should_skip_test() {
351 eprintln!("Skipping!");
352 return;
353 }
354
355 let r = runfiles::Runfiles::create().unwrap();
356 let metadata = run(
357 "crate_combined_features",
358 HashMap::from([(
359 runfiles::rlocation!(
360 r,
361 "rules_rust/crate_universe/test_data/metadata/crate_combined_features/Cargo.toml"
362 )
363 .to_string_lossy()
364 .to_string(),
365 "//:test_input".to_string(),
366 )]),
367 "rules_rust/crate_universe/test_data/metadata/crate_combined_features/Cargo.lock",
368 );
369
370 // serde appears twice in the list of dependencies, with and without derive features
371 assert_eq!(
372 metadata["metadata"]["cargo-bazel"]["tree_metadata"]["serde 1.0.158"]["common"],
373 json!({
374 "deps": [
375 "serde_derive 1.0.158",
376 ],
377 "features": [
378 "default",
379 "derive",
380 "serde_derive",
381 "std",
382 ],
383 })
384 );
385 }
386
387 // See crate_universe/test_data/metadata/target_cfg_features/Cargo.toml for input.
388 #[test]
resolver_2_deps()389 fn resolver_2_deps() {
390 if should_skip_test() {
391 eprintln!("Skipping!");
392 return;
393 }
394
395 let r = runfiles::Runfiles::create().unwrap();
396 let metadata = run(
397 "resolver_2_deps_test",
398 HashMap::from([(
399 runfiles::rlocation!(
400 r,
401 "rules_rust/crate_universe/test_data/metadata/resolver_2_deps/Cargo.toml"
402 )
403 .to_string_lossy()
404 .to_string(),
405 "//:test_input".to_string(),
406 )]),
407 "rules_rust/crate_universe/test_data/metadata/resolver_2_deps/Cargo.lock",
408 );
409
410 assert_eq!(
411 metadata["metadata"]["cargo-bazel"]["tree_metadata"]["tokio 1.37.0"],
412 json!({
413 "common": {
414 "deps": [
415 "bytes 1.6.0",
416 "pin-project-lite 0.2.14",
417 ],
418 "features": [
419 "bytes",
420 "default",
421 "io-util",
422 ],
423 },
424 // Note that there is no `wasm32-unknown-unknown` entry since all it's dependencies
425 // are common. Also note that `mio` is unique to these platforms as it's something
426 // that should be excluded from Wasm platforms.
427 "selects": {
428 "x86_64-apple-darwin": {
429 "deps": [
430 "libc 0.2.153",
431 "mio 0.8.11",
432 "socket2 0.5.7",
433 ],
434 "features": [
435 "io-std",
436 "libc",
437 "mio",
438 "net",
439 "rt",
440 "socket2",
441 "sync",
442 "time",
443 ],
444 },
445 "x86_64-pc-windows-msvc": {
446 "deps": [
447 "mio 0.8.11",
448 "socket2 0.5.7",
449 "windows-sys 0.48.0",
450 ],
451 "features": [
452 "io-std",
453 "libc",
454 "mio",
455 "net",
456 "rt",
457 "socket2",
458 "sync",
459 "time",
460 "windows-sys",
461 ],
462 },
463 "x86_64-unknown-linux-gnu": {
464 "deps": [
465 "libc 0.2.153",
466 "mio 0.8.11",
467 "socket2 0.5.7",
468 ],
469 "features": [
470 "io-std",
471 "libc",
472 "mio",
473 "net",
474 "rt",
475 "socket2",
476 "sync",
477 "time",
478 ],
479 },
480 },
481 })
482 );
483
484 assert_eq!(
485 metadata["metadata"]["cargo-bazel"]["tree_metadata"]["iana-time-zone 0.1.60"],
486 json!({
487 // Note linux is not present since linux has no unique dependencies or features
488 // for this crate.
489 "selects": {
490 "wasm32-unknown-unknown": {
491 "deps": [
492 "js-sys 0.3.69",
493 "wasm-bindgen 0.2.92",
494 ],
495 },
496 "x86_64-apple-darwin": {
497 "deps": [
498 "core-foundation-sys 0.8.6",
499 ],
500 },
501 "x86_64-pc-windows-msvc": {
502 "deps": [
503 "windows-core 0.52.0",
504 ],
505 },
506 },
507 })
508 );
509 }
510