xref: /aosp_15_r20/external/bazelbuild-rules_rust/crate_universe/tests/cargo_integration_test.rs (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
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