rust_test.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. // Copyright 2019 The Android Open Source Project
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package rust
  15. import (
  16. "os"
  17. "runtime"
  18. "strings"
  19. "testing"
  20. "github.com/google/blueprint/proptools"
  21. "android/soong/android"
  22. "android/soong/genrule"
  23. )
  24. func TestMain(m *testing.M) {
  25. os.Exit(m.Run())
  26. }
  27. var prepareForRustTest = android.GroupFixturePreparers(
  28. android.PrepareForTestWithArchMutator,
  29. android.PrepareForTestWithDefaults,
  30. android.PrepareForTestWithPrebuilts,
  31. genrule.PrepareForTestWithGenRuleBuildComponents,
  32. PrepareForTestWithRustIncludeVndk,
  33. android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
  34. variables.DeviceVndkVersion = StringPtr("current")
  35. variables.ProductVndkVersion = StringPtr("current")
  36. variables.Platform_vndk_version = StringPtr("29")
  37. }),
  38. )
  39. var rustMockedFiles = android.MockFS{
  40. "foo.rs": nil,
  41. "foo.c": nil,
  42. "src/bar.rs": nil,
  43. "src/any.h": nil,
  44. "c_includes/c_header.h": nil,
  45. "rust_includes/rust_headers.h": nil,
  46. "proto.proto": nil,
  47. "proto/buf.proto": nil,
  48. "buf.proto": nil,
  49. "foo.proto": nil,
  50. "liby.so": nil,
  51. "libz.so": nil,
  52. "data.txt": nil,
  53. "liblog.map.txt": nil,
  54. }
  55. // testRust returns a TestContext in which a basic environment has been setup.
  56. // This environment contains a few mocked files. See rustMockedFiles for the list of these files.
  57. func testRust(t *testing.T, bp string) *android.TestContext {
  58. skipTestIfOsNotSupported(t)
  59. result := android.GroupFixturePreparers(
  60. prepareForRustTest,
  61. rustMockedFiles.AddToFixture(),
  62. ).
  63. RunTestWithBp(t, bp)
  64. return result.TestContext
  65. }
  66. func testRustVndk(t *testing.T, bp string) *android.TestContext {
  67. return testRustVndkFs(t, bp, rustMockedFiles)
  68. }
  69. const (
  70. sharedVendorVariant = "android_vendor.29_arm64_armv8-a_shared"
  71. rlibVendorVariant = "android_vendor.29_arm64_armv8-a_rlib_rlib-std"
  72. sharedRecoveryVariant = "android_recovery_arm64_armv8-a_shared"
  73. rlibRecoveryVariant = "android_recovery_arm64_armv8-a_rlib_rlib-std"
  74. binaryCoreVariant = "android_arm64_armv8-a"
  75. binaryVendorVariant = "android_vendor.29_arm64_armv8-a"
  76. binaryProductVariant = "android_product.29_arm64_armv8-a"
  77. binaryRecoveryVariant = "android_recovery_arm64_armv8-a"
  78. )
  79. func testRustVndkFs(t *testing.T, bp string, fs android.MockFS) *android.TestContext {
  80. return testRustVndkFsVersions(t, bp, fs, "current", "current", "29")
  81. }
  82. func testRustVndkFsVersions(t *testing.T, bp string, fs android.MockFS, device_version, product_version, vndk_version string) *android.TestContext {
  83. skipTestIfOsNotSupported(t)
  84. result := android.GroupFixturePreparers(
  85. prepareForRustTest,
  86. fs.AddToFixture(),
  87. android.FixtureModifyProductVariables(
  88. func(variables android.FixtureProductVariables) {
  89. variables.DeviceVndkVersion = StringPtr(device_version)
  90. variables.ProductVndkVersion = StringPtr(product_version)
  91. variables.Platform_vndk_version = StringPtr(vndk_version)
  92. },
  93. ),
  94. ).RunTestWithBp(t, bp)
  95. return result.TestContext
  96. }
  97. func testRustRecoveryFsVersions(t *testing.T, bp string, fs android.MockFS, device_version, vndk_version, recovery_version string) *android.TestContext {
  98. skipTestIfOsNotSupported(t)
  99. result := android.GroupFixturePreparers(
  100. prepareForRustTest,
  101. fs.AddToFixture(),
  102. android.FixtureModifyProductVariables(
  103. func(variables android.FixtureProductVariables) {
  104. variables.DeviceVndkVersion = StringPtr(device_version)
  105. variables.RecoverySnapshotVersion = StringPtr(recovery_version)
  106. variables.Platform_vndk_version = StringPtr(vndk_version)
  107. },
  108. ),
  109. ).RunTestWithBp(t, bp)
  110. return result.TestContext
  111. }
  112. // testRustCov returns a TestContext in which a basic environment has been
  113. // setup. This environment explicitly enables coverage.
  114. func testRustCov(t *testing.T, bp string) *android.TestContext {
  115. skipTestIfOsNotSupported(t)
  116. result := android.GroupFixturePreparers(
  117. prepareForRustTest,
  118. rustMockedFiles.AddToFixture(),
  119. android.FixtureModifyProductVariables(
  120. func(variables android.FixtureProductVariables) {
  121. variables.ClangCoverage = proptools.BoolPtr(true)
  122. variables.Native_coverage = proptools.BoolPtr(true)
  123. variables.NativeCoveragePaths = []string{"*"}
  124. },
  125. ),
  126. ).RunTestWithBp(t, bp)
  127. return result.TestContext
  128. }
  129. // testRustError ensures that at least one error was raised and its value
  130. // matches the pattern provided. The error can be either in the parsing of the
  131. // Blueprint or when generating the build actions.
  132. func testRustError(t *testing.T, pattern string, bp string) {
  133. skipTestIfOsNotSupported(t)
  134. android.GroupFixturePreparers(
  135. prepareForRustTest,
  136. rustMockedFiles.AddToFixture(),
  137. ).
  138. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
  139. RunTestWithBp(t, bp)
  140. }
  141. // testRustVndkError is similar to testRustError, but can be used to test VNDK-related errors.
  142. func testRustVndkError(t *testing.T, pattern string, bp string) {
  143. testRustVndkFsError(t, pattern, bp, rustMockedFiles)
  144. }
  145. func testRustVndkFsError(t *testing.T, pattern string, bp string, fs android.MockFS) {
  146. skipTestIfOsNotSupported(t)
  147. android.GroupFixturePreparers(
  148. prepareForRustTest,
  149. fs.AddToFixture(),
  150. android.FixtureModifyProductVariables(
  151. func(variables android.FixtureProductVariables) {
  152. variables.DeviceVndkVersion = StringPtr("current")
  153. variables.ProductVndkVersion = StringPtr("current")
  154. variables.Platform_vndk_version = StringPtr("VER")
  155. },
  156. ),
  157. ).
  158. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
  159. RunTestWithBp(t, bp)
  160. }
  161. // testRustCtx is used to build a particular test environment. Unless your
  162. // tests requires a specific setup, prefer the wrapping functions: testRust,
  163. // testRustCov or testRustError.
  164. type testRustCtx struct {
  165. bp string
  166. fs map[string][]byte
  167. env map[string]string
  168. config *android.Config
  169. }
  170. func skipTestIfOsNotSupported(t *testing.T) {
  171. // TODO (b/140435149)
  172. if runtime.GOOS != "linux" {
  173. t.Skip("Rust Soong tests can only be run on Linux hosts currently")
  174. }
  175. }
  176. // Test that we can extract the link path from a lib path.
  177. func TestLinkPathFromFilePath(t *testing.T) {
  178. barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
  179. libName := linkPathFromFilePath(barPath)
  180. expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/"
  181. if libName != expectedResult {
  182. t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
  183. }
  184. }
  185. // Test to make sure dependencies are being picked up correctly.
  186. func TestDepsTracking(t *testing.T) {
  187. ctx := testRust(t, `
  188. cc_library {
  189. host_supported: true,
  190. name: "cc_stubs_dep",
  191. }
  192. rust_ffi_host_static {
  193. name: "libstatic",
  194. srcs: ["foo.rs"],
  195. crate_name: "static",
  196. }
  197. rust_ffi_host_static {
  198. name: "libwholestatic",
  199. srcs: ["foo.rs"],
  200. crate_name: "wholestatic",
  201. }
  202. rust_ffi_host_shared {
  203. name: "libshared",
  204. srcs: ["foo.rs"],
  205. crate_name: "shared",
  206. }
  207. rust_library_host_dylib {
  208. name: "libdylib",
  209. srcs: ["foo.rs"],
  210. crate_name: "dylib",
  211. }
  212. rust_library_host_rlib {
  213. name: "librlib",
  214. srcs: ["foo.rs"],
  215. crate_name: "rlib",
  216. static_libs: ["libstatic"],
  217. whole_static_libs: ["libwholestatic"],
  218. shared_libs: ["cc_stubs_dep"],
  219. }
  220. rust_proc_macro {
  221. name: "libpm",
  222. srcs: ["foo.rs"],
  223. crate_name: "pm",
  224. }
  225. rust_binary_host {
  226. name: "fizz-buzz",
  227. dylibs: ["libdylib"],
  228. rlibs: ["librlib"],
  229. proc_macros: ["libpm"],
  230. static_libs: ["libstatic"],
  231. shared_libs: ["libshared"],
  232. srcs: ["foo.rs"],
  233. }
  234. `)
  235. module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
  236. rustc := ctx.ModuleForTests("librlib", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
  237. rustLink := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustLink")
  238. // Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
  239. if !android.InList("libdylib", module.Properties.AndroidMkDylibs) {
  240. t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)")
  241. }
  242. if !android.InList("librlib.rlib-std", module.Properties.AndroidMkRlibs) {
  243. t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)")
  244. }
  245. if !android.InList("libpm", module.Properties.AndroidMkProcMacroLibs) {
  246. t.Errorf("Proc_macro dependency not detected (dependency missing from AndroidMkProcMacroLibs)")
  247. }
  248. if !android.InList("libshared", module.Properties.AndroidMkSharedLibs) {
  249. t.Errorf("Shared library dependency not detected (dependency missing from AndroidMkSharedLibs)")
  250. }
  251. if !android.InList("libstatic", module.Properties.AndroidMkStaticLibs) {
  252. t.Errorf("Static library dependency not detected (dependency missing from AndroidMkStaticLibs)")
  253. }
  254. if !strings.Contains(rustc.Args["rustcFlags"], "-lstatic=wholestatic") {
  255. t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.Args["rustcFlags"])
  256. }
  257. if !strings.Contains(rustLink.Args["linkFlags"], "cc_stubs_dep.so") {
  258. t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustLink.Args["linkFlags"])
  259. }
  260. if !android.SuffixInList(rustLink.OrderOnly.Strings(), "cc_stubs_dep.so") {
  261. t.Errorf("shared cc dep not being passed as order-only to rustc %#v", rustLink.OrderOnly.Strings())
  262. }
  263. if !android.SuffixInList(rustLink.Implicits.Strings(), "cc_stubs_dep.so.toc") {
  264. t.Errorf("shared cc dep TOC not being passed as implicit to rustc %#v", rustLink.Implicits.Strings())
  265. }
  266. }
  267. func TestSourceProviderDeps(t *testing.T) {
  268. ctx := testRust(t, `
  269. rust_binary {
  270. name: "fizz-buzz-dep",
  271. srcs: [
  272. "foo.rs",
  273. ":my_generator",
  274. ":libbindings",
  275. ],
  276. rlibs: ["libbindings"],
  277. }
  278. rust_proc_macro {
  279. name: "libprocmacro",
  280. srcs: [
  281. "foo.rs",
  282. ":my_generator",
  283. ":libbindings",
  284. ],
  285. rlibs: ["libbindings"],
  286. crate_name: "procmacro",
  287. }
  288. rust_library {
  289. name: "libfoo",
  290. srcs: [
  291. "foo.rs",
  292. ":my_generator",
  293. ":libbindings",
  294. ],
  295. rlibs: ["libbindings"],
  296. crate_name: "foo",
  297. }
  298. genrule {
  299. name: "my_generator",
  300. tools: ["any_rust_binary"],
  301. cmd: "$(location) -o $(out) $(in)",
  302. srcs: ["src/any.h"],
  303. out: ["src/any.rs"],
  304. }
  305. rust_binary_host {
  306. name: "any_rust_binary",
  307. srcs: [
  308. "foo.rs",
  309. ],
  310. }
  311. rust_bindgen {
  312. name: "libbindings",
  313. crate_name: "bindings",
  314. source_stem: "bindings",
  315. host_supported: true,
  316. wrapper_src: "src/any.h",
  317. }
  318. `)
  319. libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Rule("rustc")
  320. if !android.SuffixInList(libfoo.Implicits.Strings(), "/out/bindings.rs") {
  321. t.Errorf("rust_bindgen generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings())
  322. }
  323. if !android.SuffixInList(libfoo.Implicits.Strings(), "/out/any.rs") {
  324. t.Errorf("genrule generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings())
  325. }
  326. fizzBuzz := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Rule("rustc")
  327. if !android.SuffixInList(fizzBuzz.Implicits.Strings(), "/out/bindings.rs") {
  328. t.Errorf("rust_bindgen generated source not included as implicit input for fizz-buzz-dep; Implicits %#v", libfoo.Implicits.Strings())
  329. }
  330. if !android.SuffixInList(fizzBuzz.Implicits.Strings(), "/out/any.rs") {
  331. t.Errorf("genrule generated source not included as implicit input for fizz-buzz-dep; Implicits %#v", libfoo.Implicits.Strings())
  332. }
  333. libprocmacro := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Rule("rustc")
  334. if !android.SuffixInList(libprocmacro.Implicits.Strings(), "/out/bindings.rs") {
  335. t.Errorf("rust_bindgen generated source not included as implicit input for libprocmacro; Implicits %#v", libfoo.Implicits.Strings())
  336. }
  337. if !android.SuffixInList(libprocmacro.Implicits.Strings(), "/out/any.rs") {
  338. t.Errorf("genrule generated source not included as implicit input for libprocmacro; Implicits %#v", libfoo.Implicits.Strings())
  339. }
  340. // Check that our bindings are picked up as crate dependencies as well
  341. libfooMod := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
  342. if !android.InList("libbindings", libfooMod.Properties.AndroidMkRlibs) {
  343. t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
  344. }
  345. fizzBuzzMod := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Module().(*Module)
  346. if !android.InList("libbindings", fizzBuzzMod.Properties.AndroidMkRlibs) {
  347. t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
  348. }
  349. libprocmacroMod := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Module().(*Module)
  350. if !android.InList("libbindings.rlib-std", libprocmacroMod.Properties.AndroidMkRlibs) {
  351. t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
  352. }
  353. }
  354. func TestSourceProviderTargetMismatch(t *testing.T) {
  355. // This might error while building the dependency tree or when calling depsToPaths() depending on the lunched
  356. // target, which results in two different errors. So don't check the error, just confirm there is one.
  357. testRustError(t, ".*", `
  358. rust_proc_macro {
  359. name: "libprocmacro",
  360. srcs: [
  361. "foo.rs",
  362. ":libbindings",
  363. ],
  364. crate_name: "procmacro",
  365. }
  366. rust_bindgen {
  367. name: "libbindings",
  368. crate_name: "bindings",
  369. source_stem: "bindings",
  370. wrapper_src: "src/any.h",
  371. }
  372. `)
  373. }
  374. // Test to make sure proc_macros use host variants when building device modules.
  375. func TestProcMacroDeviceDeps(t *testing.T) {
  376. ctx := testRust(t, `
  377. rust_library_host_rlib {
  378. name: "libbar",
  379. srcs: ["foo.rs"],
  380. crate_name: "bar",
  381. }
  382. rust_proc_macro {
  383. name: "libpm",
  384. rlibs: ["libbar"],
  385. srcs: ["foo.rs"],
  386. crate_name: "pm",
  387. }
  388. rust_binary {
  389. name: "fizz-buzz",
  390. proc_macros: ["libpm"],
  391. srcs: ["foo.rs"],
  392. }
  393. `)
  394. rustc := ctx.ModuleForTests("libpm", "linux_glibc_x86_64").Rule("rustc")
  395. if !strings.Contains(rustc.Args["libFlags"], "libbar/linux_glibc_x86_64") {
  396. t.Errorf("Proc_macro is not using host variant of dependent modules.")
  397. }
  398. }
  399. // Test that no_stdlibs suppresses dependencies on rust standard libraries
  400. func TestNoStdlibs(t *testing.T) {
  401. ctx := testRust(t, `
  402. rust_binary {
  403. name: "fizz-buzz",
  404. srcs: ["foo.rs"],
  405. no_stdlibs: true,
  406. }`)
  407. module := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module)
  408. if android.InList("libstd", module.Properties.AndroidMkDylibs) {
  409. t.Errorf("no_stdlibs did not suppress dependency on libstd")
  410. }
  411. }
  412. // Test that libraries provide both 32-bit and 64-bit variants.
  413. func TestMultilib(t *testing.T) {
  414. ctx := testRust(t, `
  415. rust_library_rlib {
  416. name: "libfoo",
  417. srcs: ["foo.rs"],
  418. crate_name: "foo",
  419. }`)
  420. _ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std")
  421. _ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib_dylib-std")
  422. }
  423. // Test that library size measurements are generated.
  424. func TestLibrarySizes(t *testing.T) {
  425. ctx := testRust(t, `
  426. rust_library_dylib {
  427. name: "libwaldo",
  428. srcs: ["foo.rs"],
  429. crate_name: "waldo",
  430. }`)
  431. m := ctx.SingletonForTests("file_metrics")
  432. m.Output("unstripped/libwaldo.dylib.so.bloaty.csv")
  433. m.Output("libwaldo.dylib.so.bloaty.csv")
  434. }
  435. func assertString(t *testing.T, got, expected string) {
  436. t.Helper()
  437. if got != expected {
  438. t.Errorf("expected %q got %q", expected, got)
  439. }
  440. }