Support test fixtures in rust package

Replaces the rust specific rustTestCtx mechanism with the general test
fixtures mechanism as converting it to use preparers was not possible.

Also, removes usages of the buildDir variable and removes it as it is
no longer needed.

Bug: 181070625
Test: m nothing
Change-Id: I0176a7b6fb2d390ae23693f1e198da5124b4be63
This commit is contained in:
Paul Duffin
2021-03-07 19:18:38 +00:00
parent e0998ab561
commit 2c4ca8d73f
5 changed files with 73 additions and 141 deletions

View File

@@ -66,7 +66,7 @@ func TestClippy(t *testing.T) {
for _, tc := range clippyLintTests { for _, tc := range clippyLintTests {
t.Run("path="+tc.modulePath, func(t *testing.T) { t.Run("path="+tc.modulePath, func(t *testing.T) {
config := android.TestArchConfig(buildDir, nil, bp, fs) config := android.TestArchConfig(t.TempDir(), nil, bp, fs)
ctx := CreateTestContext(config) ctx := CreateTestContext(config)
ctx.Register() ctx.Register()
_, errs := ctx.ParseFileList(".", []string{tc.modulePath + "Android.bp"}) _, errs := ctx.ParseFileList(".", []string{tc.modulePath + "Android.bp"})

View File

@@ -153,7 +153,7 @@ func TestLints(t *testing.T) {
for _, tc := range lintTests { for _, tc := range lintTests {
t.Run("path="+tc.modulePath, func(t *testing.T) { t.Run("path="+tc.modulePath, func(t *testing.T) {
config := android.TestArchConfig(buildDir, nil, bp, fs) config := android.TestArchConfig(t.TempDir(), nil, bp, fs)
ctx := CreateTestContext(config) ctx := CreateTestContext(config)
ctx.Register() ctx.Register()
_, errs := ctx.ParseFileList(".", []string{tc.modulePath + "Android.bp"}) _, errs := ctx.ParseFileList(".", []string{tc.modulePath + "Android.bp"})

View File

@@ -27,15 +27,14 @@ import (
// testProjectJson run the generation of rust-project.json. It returns the raw // testProjectJson run the generation of rust-project.json. It returns the raw
// content of the generated file. // content of the generated file.
func testProjectJson(t *testing.T, bp string) []byte { func testProjectJson(t *testing.T, bp string) []byte {
tctx := newTestRustCtx(t, bp) result := prepareForRustTest.
tctx.env = map[string]string{"SOONG_GEN_RUST_PROJECT": "1"} Extend(android.FixtureMergeEnv(map[string]string{"SOONG_GEN_RUST_PROJECT": "1"})).
tctx.generateConfig() RunTestWithBp(t, bp)
tctx.parse(t)
// The JSON file is generated via WriteFileToOutputDir. Therefore, it // The JSON file is generated via WriteFileToOutputDir. Therefore, it
// won't appear in the Output of the TestingSingleton. Manually verify // won't appear in the Output of the TestingSingleton. Manually verify
// it exists. // it exists.
content, err := ioutil.ReadFile(filepath.Join(buildDir, rustProjectJsonFileName)) content, err := ioutil.ReadFile(filepath.Join(result.Config.BuildDir(), rustProjectJsonFileName))
if err != nil { if err != nil {
t.Errorf("rust-project.json has not been generated") t.Errorf("rust-project.json has not been generated")
} }

View File

@@ -101,7 +101,7 @@ func TestRustGrpc(t *testing.T) {
} }
// Check that we're including the exported directory from libprotobuf-cpp-full // Check that we're including the exported directory from libprotobuf-cpp-full
if w := "-Ilibprotobuf-cpp-full-includes"; !strings.Contains(cmd, w) { if w := "-I" + rustDefaultsDir + "libprotobuf-cpp-full-includes"; !strings.Contains(cmd, w) {
t.Errorf("expected %q in %q", w, cmd) t.Errorf("expected %q in %q", w, cmd)
} }

View File

@@ -15,7 +15,6 @@
package rust package rust
import ( import (
"io/ioutil"
"os" "os"
"runtime" "runtime"
"strings" "strings"
@@ -24,96 +23,24 @@ import (
"github.com/google/blueprint/proptools" "github.com/google/blueprint/proptools"
"android/soong/android" "android/soong/android"
"android/soong/cc" "android/soong/genrule"
) )
var (
buildDir string
)
func setUp() {
var err error
buildDir, err = ioutil.TempDir("", "soong_rust_test")
if err != nil {
panic(err)
}
}
func tearDown() {
os.RemoveAll(buildDir)
}
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
run := func() int { os.Exit(m.Run())
setUp()
defer tearDown()
return m.Run()
} }
os.Exit(run()) var prepareForRustTest = android.GroupFixturePreparers(
} android.PrepareForTestWithArchMutator,
android.PrepareForTestWithDefaults,
android.PrepareForTestWithPrebuilts,
// testRust returns a TestContext in which a basic environment has been setup. genrule.PrepareForTestWithGenRuleBuildComponents,
// This environment contains a few mocked files. See testRustCtx.useMockedFs
// for the list of these files.
func testRust(t *testing.T, bp string) *android.TestContext {
tctx := newTestRustCtx(t, bp)
tctx.useMockedFs()
tctx.generateConfig()
return tctx.parse(t)
}
func testRustVndk(t *testing.T, bp string) *android.TestContext { PrepareForIntegrationTestWithRust,
tctx := newTestRustCtx(t, bp) )
tctx.useMockedFs()
tctx.generateConfig()
tctx.setVndk(t)
return tctx.parse(t)
}
// testRustCov returns a TestContext in which a basic environment has been var rustMockedFiles = android.MockFS{
// setup. This environment explicitly enables coverage.
func testRustCov(t *testing.T, bp string) *android.TestContext {
tctx := newTestRustCtx(t, bp)
tctx.useMockedFs()
tctx.generateConfig()
tctx.enableCoverage(t)
return tctx.parse(t)
}
// 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) {
tctx := newTestRustCtx(t, bp)
tctx.useMockedFs()
tctx.generateConfig()
tctx.parseError(t, pattern)
}
// 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
}
// newTestRustCtx returns a new testRustCtx for the Blueprint definition argument.
func newTestRustCtx(t *testing.T, bp string) *testRustCtx {
// TODO (b/140435149)
if runtime.GOOS != "linux" {
t.Skip("Rust Soong tests can only be run on Linux hosts currently")
}
return &testRustCtx{bp: bp}
}
// useMockedFs setup a default mocked filesystem for the test environment.
func (tctx *testRustCtx) useMockedFs() {
tctx.fs = map[string][]byte{
"foo.rs": nil, "foo.rs": nil,
"foo.c": nil, "foo.c": nil,
"src/bar.rs": nil, "src/bar.rs": nil,
@@ -126,75 +53,81 @@ func (tctx *testRustCtx) useMockedFs() {
"libz.so": nil, "libz.so": nil,
"data.txt": nil, "data.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
} }
// generateConfig creates the android.Config based on the bp, fs and env func testRustVndk(t *testing.T, bp string) *android.TestContext {
// attributes of the testRustCtx. skipTestIfOsNotSupported(t)
func (tctx *testRustCtx) generateConfig() { result := android.GroupFixturePreparers(
tctx.bp = tctx.bp + GatherRequiredDepsForTest() prepareForRustTest,
tctx.bp = tctx.bp + cc.GatherRequiredDepsForTest(android.NoOsType) rustMockedFiles.AddToFixture(),
cc.GatherRequiredFilesForTest(tctx.fs) android.FixtureModifyProductVariables(
config := android.TestArchConfig(buildDir, tctx.env, tctx.bp, tctx.fs) func(variables android.FixtureProductVariables) {
tctx.config = &config variables.DeviceVndkVersion = StringPtr("current")
variables.ProductVndkVersion = StringPtr("current")
variables.Platform_vndk_version = StringPtr("VER")
},
),
).RunTestWithBp(t, bp)
return result.TestContext
} }
// enableCoverage configures the test to enable coverage. // testRustCov returns a TestContext in which a basic environment has been
func (tctx *testRustCtx) enableCoverage(t *testing.T) { // setup. This environment explicitly enables coverage.
if tctx.config == nil { func testRustCov(t *testing.T, bp string) *android.TestContext {
t.Fatalf("tctx.config not been generated yet. Please call generateConfig first.") skipTestIfOsNotSupported(t)
} result := android.GroupFixturePreparers(
tctx.config.TestProductVariables.ClangCoverage = proptools.BoolPtr(true) prepareForRustTest,
tctx.config.TestProductVariables.Native_coverage = proptools.BoolPtr(true) rustMockedFiles.AddToFixture(),
tctx.config.TestProductVariables.NativeCoveragePaths = []string{"*"} 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
} }
func (tctx *testRustCtx) setVndk(t *testing.T) { // testRustError ensures that at least one error was raised and its value
if tctx.config == nil { // matches the pattern provided. The error can be either in the parsing of the
t.Fatalf("tctx.config not been generated yet. Please call generateConfig first.") // Blueprint or when generating the build actions.
} func testRustError(t *testing.T, pattern string, bp string) {
tctx.config.TestProductVariables.DeviceVndkVersion = StringPtr("current") skipTestIfOsNotSupported(t)
tctx.config.TestProductVariables.ProductVndkVersion = StringPtr("current") android.GroupFixturePreparers(
tctx.config.TestProductVariables.Platform_vndk_version = StringPtr("VER") prepareForRustTest,
rustMockedFiles.AddToFixture(),
).
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
RunTestWithBp(t, bp)
} }
// parse validates the configuration and parses the Blueprint file. It returns // testRustCtx is used to build a particular test environment. Unless your
// a TestContext which can be used to retrieve the generated modules via // tests requires a specific setup, prefer the wrapping functions: testRust,
// ModuleForTests. // testRustCov or testRustError.
func (tctx testRustCtx) parse(t *testing.T) *android.TestContext { type testRustCtx struct {
if tctx.config == nil { bp string
t.Fatalf("tctx.config not been generated yet. Please call generateConfig first.") fs map[string][]byte
} env map[string]string
ctx := CreateTestContext(*tctx.config) config *android.Config
ctx.Register()
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(*tctx.config)
android.FailIfErrored(t, errs)
return ctx
} }
// parseError parses the Blueprint file and ensure that at least one error func skipTestIfOsNotSupported(t *testing.T) {
// matching the provided pattern is observed. // TODO (b/140435149)
func (tctx testRustCtx) parseError(t *testing.T, pattern string) { if runtime.GOOS != "linux" {
if tctx.config == nil { t.Skip("Rust Soong tests can only be run on Linux hosts currently")
t.Fatalf("tctx.config not been generated yet. Please call generateConfig first.")
} }
ctx := CreateTestContext(*tctx.config)
ctx.Register()
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
if len(errs) > 0 {
android.FailIfNoMatchingErrors(t, pattern, errs)
return
}
_, errs = ctx.PrepareBuildActions(*tctx.config)
if len(errs) > 0 {
android.FailIfNoMatchingErrors(t, pattern, errs)
return
}
t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
} }
// Test that we can extract the link path from a lib path. // Test that we can extract the link path from a lib path.