From a5f22ed6b05bc977f0fc39be4af9c12e52471c1d Mon Sep 17 00:00:00 2001 From: Chih-Hung Hsieh Date: Thu, 24 Oct 2019 20:47:54 -0700 Subject: [PATCH] Add rust_test and rust_test_host. * Rust tests are like binary files compiled with --test. New test.go follows binary.go code patterns and reuses some code in binary.go. * Generate one test per source file as testPerSrc in cc/test.go. The "all tests" variation feature of cc/test.go is not copied yet. Fix some Stem and SubName settings to make testPerSrc work. * Move cc.CheckDuplicate to android.CheckDuplicate, which is now shared by cc and rust. * Refactor tests in binary_test.go and add new test_test.go. Bug: 140938178 Test: mm in rust projects, added rust_test and rust_test_host Change-Id: Ia6fec8b4cf2572fd352ab1938a1f3c7b5cca2212 --- Android.bp | 2 + android/util.go | 11 +++++ cc/test.go | 13 +---- rust/androidmk.go | 7 +++ rust/binary_test.go | 17 +++++-- rust/rust.go | 9 ++-- rust/test.go | 116 ++++++++++++++++++++++++++++++++++++++++++++ rust/test_test.go | 43 ++++++++++++++++ rust/testing.go | 3 ++ 9 files changed, 202 insertions(+), 19 deletions(-) create mode 100644 rust/test.go create mode 100644 rust/test_test.go diff --git a/Android.bp b/Android.bp index 05972fd36..8d0c1ea6a 100644 --- a/Android.bp +++ b/Android.bp @@ -366,6 +366,7 @@ bootstrap_go_package { "rust/prebuilt.go", "rust/proc_macro.go", "rust/rust.go", + "rust/test.go", "rust/testing.go", ], testSrcs: [ @@ -373,6 +374,7 @@ bootstrap_go_package { "rust/compiler_test.go", "rust/library_test.go", "rust/rust_test.go", + "rust/test_test.go", ], pluginFor: ["soong_build"], } diff --git a/android/util.go b/android/util.go index 71ded5e07..ddbe1cd1d 100644 --- a/android/util.go +++ b/android/util.go @@ -352,3 +352,14 @@ func ShardStrings(s []string, shardSize int) [][]string { } return ret } + +func CheckDuplicate(values []string) (duplicate string, found bool) { + seen := make(map[string]string) + for _, v := range values { + if duplicate, found = seen[v]; found { + return + } + seen[v] = v + } + return +} diff --git a/cc/test.go b/cc/test.go index 0e66e288e..5c49d6e2b 100644 --- a/cc/test.go +++ b/cc/test.go @@ -173,7 +173,7 @@ func TestPerSrcMutator(mctx android.BottomUpMutatorContext) { if test, ok := m.linker.(testPerSrc); ok { numTests := len(test.srcs()) if test.testPerSrc() && numTests > 0 { - if duplicate, found := checkDuplicate(test.srcs()); found { + if duplicate, found := android.CheckDuplicate(test.srcs()); found { mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate) return } @@ -206,17 +206,6 @@ func TestPerSrcMutator(mctx android.BottomUpMutatorContext) { } } -func checkDuplicate(values []string) (duplicate string, found bool) { - seen := make(map[string]string) - for _, v := range values { - if duplicate, found = seen[v]; found { - return - } - seen[v] = v - } - return -} - type testDecorator struct { Properties TestProperties linker *baseLinker diff --git a/rust/androidmk.go b/rust/androidmk.go index f933cfbcf..49115f219 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -72,6 +72,8 @@ func (mod *Module) AndroidMk() android.AndroidMkData { mod.subAndroidMk(&ret, mod.compiler) + ret.SubName += mod.Properties.SubName + return ret } @@ -85,6 +87,11 @@ func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.Andr }) } +func (test *testBinaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + test.binaryDecorator.AndroidMk(ctx, ret) + ret.SubName = "_" + String(test.baseCompiler.Properties.Stem) +} + func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { ctx.subAndroidMk(ret, library.baseCompiler) diff --git a/rust/binary_test.go b/rust/binary_test.go index cd41fcfae..ab2dae153 100644 --- a/rust/binary_test.go +++ b/rust/binary_test.go @@ -36,11 +36,20 @@ func TestPreferDynamicBinary(t *testing.T) { fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz") fizzBuzzDynamic := ctx.ModuleForTests("fizz-buzz-dynamic", "linux_glibc_x86_64").Output("fizz-buzz-dynamic") - if !strings.Contains(fizzBuzzDynamic.Args["rustcFlags"], "prefer-dynamic") { - t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", fizzBuzzDynamic.Args["rustcFlags"]) + // Do not compile binary modules with the --test flag. + flags := fizzBuzzDynamic.Args["rustcFlags"] + if strings.Contains(flags, "--test") { + t.Errorf("extra --test flag, rustcFlags: %#v", flags) + } + if !strings.Contains(flags, "prefer-dynamic") { + t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", flags) } - if strings.Contains(fizzBuzz.Args["rustcFlags"], "prefer-dynamic") { - t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", fizzBuzz.Args["rustcFlags"]) + flags = fizzBuzz.Args["rustcFlags"] + if strings.Contains(flags, "--test") { + t.Errorf("extra --test flag, rustcFlags: %#v", flags) + } + if strings.Contains(flags, "prefer-dynamic") { + t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", flags) } } diff --git a/rust/rust.go b/rust/rust.go index ce81b9152..ec3b59086 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -39,6 +39,7 @@ func init() { android.RegisterModuleType("rust_defaults", defaultsFactory) android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("rust_libraries", LibraryMutator).Parallel() + ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel() }) pctx.Import("android/soong/rust/config") } @@ -58,6 +59,7 @@ type BaseProperties struct { AndroidMkProcMacroLibs []string AndroidMkSharedLibs []string AndroidMkStaticLibs []string + SubName string `blueprint:"mutated"` } type Module struct { @@ -495,9 +497,10 @@ type dependencyTag struct { } var ( - rlibDepTag = dependencyTag{name: "rlibTag", library: true} - dylibDepTag = dependencyTag{name: "dylib", library: true} - procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true} + rlibDepTag = dependencyTag{name: "rlibTag", library: true} + dylibDepTag = dependencyTag{name: "dylib", library: true} + procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true} + testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"} ) func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { diff --git a/rust/test.go b/rust/test.go new file mode 100644 index 000000000..816e3c731 --- /dev/null +++ b/rust/test.go @@ -0,0 +1,116 @@ +// 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 ( + "path/filepath" + "strings" + + "android/soong/android" +) + +// A test module is a binary module with extra --test compiler flag +// and different default installation directory. +// In golang, inheriance is written as a component. +type testBinaryDecorator struct { + *binaryDecorator +} + +func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testBinaryDecorator) { + module := newModule(hod, android.MultilibFirst) + + test := &testBinaryDecorator{ + binaryDecorator: &binaryDecorator{ + // TODO(chh): set up dir64? + baseCompiler: NewBaseCompiler("testcases", ""), + }, + } + + module.compiler = test + + return module, test +} + +func (test *testBinaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { + flags = test.binaryDecorator.compilerFlags(ctx, flags) + flags.RustFlags = append(flags.RustFlags, "--test") + return flags +} + +func init() { + // Rust tests are binary files built with --test. + android.RegisterModuleType("rust_test", RustTestFactory) + android.RegisterModuleType("rust_test_host", RustTestHostFactory) +} + +func RustTestFactory() android.Module { + module, _ := NewRustTest(android.HostAndDeviceSupported) + return module.Init() +} + +func RustTestHostFactory() android.Module { + module, _ := NewRustTest(android.HostSupported) + return module.Init() +} + +func (test *testBinaryDecorator) testPerSrc() bool { + return true +} + +func (test *testBinaryDecorator) srcs() []string { + return test.Properties.Srcs +} + +func (test *testBinaryDecorator) setSrc(name, src string) { + test.Properties.Srcs = []string{src} + test.baseCompiler.Properties.Stem = StringPtr(name) +} + +func (test *testBinaryDecorator) unsetSrc() { + test.Properties.Srcs = nil + test.baseCompiler.Properties.Stem = StringPtr("") +} + +type testPerSrc interface { + testPerSrc() bool + srcs() []string + setSrc(string, string) + unsetSrc() +} + +var _ testPerSrc = (*testBinaryDecorator)(nil) + +func TestPerSrcMutator(mctx android.BottomUpMutatorContext) { + if m, ok := mctx.Module().(*Module); ok { + if test, ok := m.compiler.(testPerSrc); ok { + numTests := len(test.srcs()) + if test.testPerSrc() && numTests > 0 { + if duplicate, found := android.CheckDuplicate(test.srcs()); found { + mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate) + return + } + testNames := make([]string, numTests) + for i, src := range test.srcs() { + testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src)) + } + // TODO(chh): Add an "all tests" variation like cc/test.go? + tests := mctx.CreateLocalVariations(testNames...) + for i, src := range test.srcs() { + tests[i].(*Module).compiler.(testPerSrc).setSrc(testNames[i], src) + } + } + } + } +} diff --git a/rust/test_test.go b/rust/test_test.go new file mode 100644 index 000000000..aa4c3c8cb --- /dev/null +++ b/rust/test_test.go @@ -0,0 +1,43 @@ +// 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 ( + "strings" + "testing" +) + +// Check if rust_test_host accepts multiple source files and applies --test flag. +func TestRustTest(t *testing.T) { + ctx := testRust(t, ` + rust_test_host { + name: "my_test", + srcs: ["foo.rs", "src/bar.rs"], + relative_install_path: "rust/my-test", + }`) + + for _, name := range []string{"foo", "bar"} { + testingModule := ctx.ModuleForTests("my_test", "linux_glibc_x86_64_"+name) + testingBuildParams := testingModule.Output(name) + rustcFlags := testingBuildParams.Args["rustcFlags"] + if !strings.Contains(rustcFlags, "--test") { + t.Errorf("%v missing --test flag, rustcFlags: %#v", name, rustcFlags) + } + outPath := "/my_test/linux_glibc_x86_64_" + name + "/" + name + if !strings.Contains(testingBuildParams.Output.String(), outPath) { + t.Errorf("wrong output: %v expect: %v", testingBuildParams.Output, outPath) + } + } +} diff --git a/rust/testing.go b/rust/testing.go index cd6308434..24defa634 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -168,6 +168,8 @@ func CreateTestContext(bp string) *android.TestContext { ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory)) ctx.RegisterModuleType("rust_binary", android.ModuleFactoryAdaptor(RustBinaryFactory)) ctx.RegisterModuleType("rust_binary_host", android.ModuleFactoryAdaptor(RustBinaryHostFactory)) + ctx.RegisterModuleType("rust_test", android.ModuleFactoryAdaptor(RustTestFactory)) + ctx.RegisterModuleType("rust_test_host", android.ModuleFactoryAdaptor(RustTestHostFactory)) ctx.RegisterModuleType("rust_library", android.ModuleFactoryAdaptor(RustLibraryFactory)) ctx.RegisterModuleType("rust_library_host", android.ModuleFactoryAdaptor(RustLibraryHostFactory)) ctx.RegisterModuleType("rust_library_host_rlib", android.ModuleFactoryAdaptor(RustLibraryRlibHostFactory)) @@ -190,6 +192,7 @@ func CreateTestContext(bp string) *android.TestContext { // rust mutators ctx.BottomUp("rust_libraries", LibraryMutator).Parallel() + ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel() }) bp = bp + GatherRequiredDepsForTest()