123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488 |
- // Copyright 2019 The Android Open Source Project
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package rust
- import (
- "os"
- "runtime"
- "strings"
- "testing"
- "github.com/google/blueprint/proptools"
- "android/soong/android"
- "android/soong/genrule"
- )
- func TestMain(m *testing.M) {
- os.Exit(m.Run())
- }
- var prepareForRustTest = android.GroupFixturePreparers(
- android.PrepareForTestWithArchMutator,
- android.PrepareForTestWithDefaults,
- android.PrepareForTestWithPrebuilts,
- genrule.PrepareForTestWithGenRuleBuildComponents,
- PrepareForTestWithRustIncludeVndk,
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.DeviceVndkVersion = StringPtr("current")
- variables.ProductVndkVersion = StringPtr("current")
- variables.Platform_vndk_version = StringPtr("29")
- }),
- )
- var rustMockedFiles = android.MockFS{
- "foo.rs": nil,
- "foo.c": nil,
- "src/bar.rs": nil,
- "src/any.h": nil,
- "c_includes/c_header.h": nil,
- "rust_includes/rust_headers.h": nil,
- "proto.proto": nil,
- "proto/buf.proto": nil,
- "buf.proto": nil,
- "foo.proto": nil,
- "liby.so": nil,
- "libz.so": nil,
- "data.txt": nil,
- "liblog.map.txt": nil,
- }
- // testRust returns a TestContext in which a basic environment has been setup.
- // This environment contains a few mocked files. See rustMockedFiles for the list of these files.
- func testRust(t *testing.T, bp string) *android.TestContext {
- skipTestIfOsNotSupported(t)
- result := android.GroupFixturePreparers(
- prepareForRustTest,
- rustMockedFiles.AddToFixture(),
- ).
- RunTestWithBp(t, bp)
- return result.TestContext
- }
- func testRustVndk(t *testing.T, bp string) *android.TestContext {
- return testRustVndkFs(t, bp, rustMockedFiles)
- }
- const (
- sharedVendorVariant = "android_vendor.29_arm64_armv8-a_shared"
- rlibVendorVariant = "android_vendor.29_arm64_armv8-a_rlib_rlib-std"
- sharedRecoveryVariant = "android_recovery_arm64_armv8-a_shared"
- rlibRecoveryVariant = "android_recovery_arm64_armv8-a_rlib_rlib-std"
- binaryCoreVariant = "android_arm64_armv8-a"
- binaryVendorVariant = "android_vendor.29_arm64_armv8-a"
- binaryProductVariant = "android_product.29_arm64_armv8-a"
- binaryRecoveryVariant = "android_recovery_arm64_armv8-a"
- )
- func testRustVndkFs(t *testing.T, bp string, fs android.MockFS) *android.TestContext {
- return testRustVndkFsVersions(t, bp, fs, "current", "current", "29")
- }
- func testRustVndkFsVersions(t *testing.T, bp string, fs android.MockFS, device_version, product_version, vndk_version string) *android.TestContext {
- skipTestIfOsNotSupported(t)
- result := android.GroupFixturePreparers(
- prepareForRustTest,
- fs.AddToFixture(),
- android.FixtureModifyProductVariables(
- func(variables android.FixtureProductVariables) {
- variables.DeviceVndkVersion = StringPtr(device_version)
- variables.ProductVndkVersion = StringPtr(product_version)
- variables.Platform_vndk_version = StringPtr(vndk_version)
- },
- ),
- ).RunTestWithBp(t, bp)
- return result.TestContext
- }
- func testRustRecoveryFsVersions(t *testing.T, bp string, fs android.MockFS, device_version, vndk_version, recovery_version string) *android.TestContext {
- skipTestIfOsNotSupported(t)
- result := android.GroupFixturePreparers(
- prepareForRustTest,
- fs.AddToFixture(),
- android.FixtureModifyProductVariables(
- func(variables android.FixtureProductVariables) {
- variables.DeviceVndkVersion = StringPtr(device_version)
- variables.RecoverySnapshotVersion = StringPtr(recovery_version)
- variables.Platform_vndk_version = StringPtr(vndk_version)
- },
- ),
- ).RunTestWithBp(t, bp)
- return result.TestContext
- }
- // testRustCov returns a TestContext in which a basic environment has been
- // setup. This environment explicitly enables coverage.
- func testRustCov(t *testing.T, bp string) *android.TestContext {
- skipTestIfOsNotSupported(t)
- result := android.GroupFixturePreparers(
- prepareForRustTest,
- rustMockedFiles.AddToFixture(),
- android.FixtureModifyProductVariables(
- func(variables android.FixtureProductVariables) {
- variables.ClangCoverage = proptools.BoolPtr(true)
- variables.Native_coverage = proptools.BoolPtr(true)
- variables.NativeCoveragePaths = []string{"*"}
- },
- ),
- ).RunTestWithBp(t, bp)
- return result.TestContext
- }
- // testRustError ensures that at least one error was raised and its value
- // matches the pattern provided. The error can be either in the parsing of the
- // Blueprint or when generating the build actions.
- func testRustError(t *testing.T, pattern string, bp string) {
- skipTestIfOsNotSupported(t)
- android.GroupFixturePreparers(
- prepareForRustTest,
- rustMockedFiles.AddToFixture(),
- ).
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
- RunTestWithBp(t, bp)
- }
- // testRustVndkError is similar to testRustError, but can be used to test VNDK-related errors.
- func testRustVndkError(t *testing.T, pattern string, bp string) {
- testRustVndkFsError(t, pattern, bp, rustMockedFiles)
- }
- func testRustVndkFsError(t *testing.T, pattern string, bp string, fs android.MockFS) {
- skipTestIfOsNotSupported(t)
- android.GroupFixturePreparers(
- prepareForRustTest,
- fs.AddToFixture(),
- android.FixtureModifyProductVariables(
- func(variables android.FixtureProductVariables) {
- variables.DeviceVndkVersion = StringPtr("current")
- variables.ProductVndkVersion = StringPtr("current")
- variables.Platform_vndk_version = StringPtr("VER")
- },
- ),
- ).
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
- RunTestWithBp(t, bp)
- }
- // testRustCtx is used to build a particular test environment. Unless your
- // tests requires a specific setup, prefer the wrapping functions: testRust,
- // testRustCov or testRustError.
- type testRustCtx struct {
- bp string
- fs map[string][]byte
- env map[string]string
- config *android.Config
- }
- func skipTestIfOsNotSupported(t *testing.T) {
- // TODO (b/140435149)
- if runtime.GOOS != "linux" {
- t.Skip("Rust Soong tests can only be run on Linux hosts currently")
- }
- }
- // Test that we can extract the link path from a lib path.
- func TestLinkPathFromFilePath(t *testing.T) {
- barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
- libName := linkPathFromFilePath(barPath)
- expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/"
- if libName != expectedResult {
- t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
- }
- }
- // Test to make sure dependencies are being picked up correctly.
- func TestDepsTracking(t *testing.T) {
- ctx := testRust(t, `
- cc_library {
- host_supported: true,
- name: "cc_stubs_dep",
- }
- rust_ffi_host_static {
- name: "libstatic",
- srcs: ["foo.rs"],
- crate_name: "static",
- }
- rust_ffi_host_static {
- name: "libwholestatic",
- srcs: ["foo.rs"],
- crate_name: "wholestatic",
- }
- rust_ffi_host_shared {
- name: "libshared",
- srcs: ["foo.rs"],
- crate_name: "shared",
- }
- rust_library_host_dylib {
- name: "libdylib",
- srcs: ["foo.rs"],
- crate_name: "dylib",
- }
- rust_library_host_rlib {
- name: "librlib",
- srcs: ["foo.rs"],
- crate_name: "rlib",
- static_libs: ["libstatic"],
- whole_static_libs: ["libwholestatic"],
- shared_libs: ["cc_stubs_dep"],
- }
- rust_proc_macro {
- name: "libpm",
- srcs: ["foo.rs"],
- crate_name: "pm",
- }
- rust_binary_host {
- name: "fizz-buzz",
- dylibs: ["libdylib"],
- rlibs: ["librlib"],
- proc_macros: ["libpm"],
- static_libs: ["libstatic"],
- shared_libs: ["libshared"],
- srcs: ["foo.rs"],
- }
- `)
- module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
- rustc := ctx.ModuleForTests("librlib", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
- rustLink := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustLink")
- // Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
- if !android.InList("libdylib", module.Properties.AndroidMkDylibs) {
- t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)")
- }
- if !android.InList("librlib.rlib-std", module.Properties.AndroidMkRlibs) {
- t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)")
- }
- if !android.InList("libpm", module.Properties.AndroidMkProcMacroLibs) {
- t.Errorf("Proc_macro dependency not detected (dependency missing from AndroidMkProcMacroLibs)")
- }
- if !android.InList("libshared", module.Properties.AndroidMkSharedLibs) {
- t.Errorf("Shared library dependency not detected (dependency missing from AndroidMkSharedLibs)")
- }
- if !android.InList("libstatic", module.Properties.AndroidMkStaticLibs) {
- t.Errorf("Static library dependency not detected (dependency missing from AndroidMkStaticLibs)")
- }
- if !strings.Contains(rustc.Args["rustcFlags"], "-lstatic=wholestatic") {
- t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.Args["rustcFlags"])
- }
- if !strings.Contains(rustLink.Args["linkFlags"], "cc_stubs_dep.so") {
- t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustLink.Args["linkFlags"])
- }
- if !android.SuffixInList(rustLink.OrderOnly.Strings(), "cc_stubs_dep.so") {
- t.Errorf("shared cc dep not being passed as order-only to rustc %#v", rustLink.OrderOnly.Strings())
- }
- if !android.SuffixInList(rustLink.Implicits.Strings(), "cc_stubs_dep.so.toc") {
- t.Errorf("shared cc dep TOC not being passed as implicit to rustc %#v", rustLink.Implicits.Strings())
- }
- }
- func TestSourceProviderDeps(t *testing.T) {
- ctx := testRust(t, `
- rust_binary {
- name: "fizz-buzz-dep",
- srcs: [
- "foo.rs",
- ":my_generator",
- ":libbindings",
- ],
- rlibs: ["libbindings"],
- }
- rust_proc_macro {
- name: "libprocmacro",
- srcs: [
- "foo.rs",
- ":my_generator",
- ":libbindings",
- ],
- rlibs: ["libbindings"],
- crate_name: "procmacro",
- }
- rust_library {
- name: "libfoo",
- srcs: [
- "foo.rs",
- ":my_generator",
- ":libbindings",
- ],
- rlibs: ["libbindings"],
- crate_name: "foo",
- }
- genrule {
- name: "my_generator",
- tools: ["any_rust_binary"],
- cmd: "$(location) -o $(out) $(in)",
- srcs: ["src/any.h"],
- out: ["src/any.rs"],
- }
- rust_binary_host {
- name: "any_rust_binary",
- srcs: [
- "foo.rs",
- ],
- }
- rust_bindgen {
- name: "libbindings",
- crate_name: "bindings",
- source_stem: "bindings",
- host_supported: true,
- wrapper_src: "src/any.h",
- }
- `)
- libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Rule("rustc")
- if !android.SuffixInList(libfoo.Implicits.Strings(), "/out/bindings.rs") {
- t.Errorf("rust_bindgen generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings())
- }
- if !android.SuffixInList(libfoo.Implicits.Strings(), "/out/any.rs") {
- t.Errorf("genrule generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings())
- }
- fizzBuzz := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Rule("rustc")
- if !android.SuffixInList(fizzBuzz.Implicits.Strings(), "/out/bindings.rs") {
- t.Errorf("rust_bindgen generated source not included as implicit input for fizz-buzz-dep; Implicits %#v", libfoo.Implicits.Strings())
- }
- if !android.SuffixInList(fizzBuzz.Implicits.Strings(), "/out/any.rs") {
- t.Errorf("genrule generated source not included as implicit input for fizz-buzz-dep; Implicits %#v", libfoo.Implicits.Strings())
- }
- libprocmacro := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Rule("rustc")
- if !android.SuffixInList(libprocmacro.Implicits.Strings(), "/out/bindings.rs") {
- t.Errorf("rust_bindgen generated source not included as implicit input for libprocmacro; Implicits %#v", libfoo.Implicits.Strings())
- }
- if !android.SuffixInList(libprocmacro.Implicits.Strings(), "/out/any.rs") {
- t.Errorf("genrule generated source not included as implicit input for libprocmacro; Implicits %#v", libfoo.Implicits.Strings())
- }
- // Check that our bindings are picked up as crate dependencies as well
- libfooMod := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
- if !android.InList("libbindings", libfooMod.Properties.AndroidMkRlibs) {
- t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
- }
- fizzBuzzMod := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Module().(*Module)
- if !android.InList("libbindings", fizzBuzzMod.Properties.AndroidMkRlibs) {
- t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
- }
- libprocmacroMod := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Module().(*Module)
- if !android.InList("libbindings.rlib-std", libprocmacroMod.Properties.AndroidMkRlibs) {
- t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
- }
- }
- func TestSourceProviderTargetMismatch(t *testing.T) {
- // This might error while building the dependency tree or when calling depsToPaths() depending on the lunched
- // target, which results in two different errors. So don't check the error, just confirm there is one.
- testRustError(t, ".*", `
- rust_proc_macro {
- name: "libprocmacro",
- srcs: [
- "foo.rs",
- ":libbindings",
- ],
- crate_name: "procmacro",
- }
- rust_bindgen {
- name: "libbindings",
- crate_name: "bindings",
- source_stem: "bindings",
- wrapper_src: "src/any.h",
- }
- `)
- }
- // Test to make sure proc_macros use host variants when building device modules.
- func TestProcMacroDeviceDeps(t *testing.T) {
- ctx := testRust(t, `
- rust_library_host_rlib {
- name: "libbar",
- srcs: ["foo.rs"],
- crate_name: "bar",
- }
- rust_proc_macro {
- name: "libpm",
- rlibs: ["libbar"],
- srcs: ["foo.rs"],
- crate_name: "pm",
- }
- rust_binary {
- name: "fizz-buzz",
- proc_macros: ["libpm"],
- srcs: ["foo.rs"],
- }
- `)
- rustc := ctx.ModuleForTests("libpm", "linux_glibc_x86_64").Rule("rustc")
- if !strings.Contains(rustc.Args["libFlags"], "libbar/linux_glibc_x86_64") {
- t.Errorf("Proc_macro is not using host variant of dependent modules.")
- }
- }
- // Test that no_stdlibs suppresses dependencies on rust standard libraries
- func TestNoStdlibs(t *testing.T) {
- ctx := testRust(t, `
- rust_binary {
- name: "fizz-buzz",
- srcs: ["foo.rs"],
- no_stdlibs: true,
- }`)
- module := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module)
- if android.InList("libstd", module.Properties.AndroidMkDylibs) {
- t.Errorf("no_stdlibs did not suppress dependency on libstd")
- }
- }
- // Test that libraries provide both 32-bit and 64-bit variants.
- func TestMultilib(t *testing.T) {
- ctx := testRust(t, `
- rust_library_rlib {
- name: "libfoo",
- srcs: ["foo.rs"],
- crate_name: "foo",
- }`)
- _ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std")
- _ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib_dylib-std")
- }
- // Test that library size measurements are generated.
- func TestLibrarySizes(t *testing.T) {
- ctx := testRust(t, `
- rust_library_dylib {
- name: "libwaldo",
- srcs: ["foo.rs"],
- crate_name: "waldo",
- }`)
- m := ctx.SingletonForTests("file_metrics")
- m.Output("unstripped/libwaldo.dylib.so.bloaty.csv")
- m.Output("libwaldo.dylib.so.bloaty.csv")
- }
- func assertString(t *testing.T, got, expected string) {
- t.Helper()
- if got != expected {
- t.Errorf("expected %q got %q", expected, got)
- }
- }
|