diff options
| author | Yuexi Ma <yuexima@google.com> | 2021-03-17 01:40:51 +0000 |
|---|---|---|
| committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-03-17 01:40:51 +0000 |
| commit | 55626259d0f0186873acd2315247bcfaf00dc97d (patch) | |
| tree | d3f1c618c92a13154896c62df630182789cf7b9b | |
| parent | b649ec650d9b76dbb99b18a2937bda84900d7398 (diff) | |
| parent | f4dfe227ce2b488142af9f4b699ac396c9259605 (diff) | |
| download | platform_test_app_compat_csuite-55626259d0f0186873acd2315247bcfaf00dc97d.tar.gz platform_test_app_compat_csuite-55626259d0f0186873acd2315247bcfaf00dc97d.tar.bz2 platform_test_app_compat_csuite-55626259d0f0186873acd2315247bcfaf00dc97d.zip | |
Merge "Add a csuite_test Soong rule"
| -rw-r--r-- | PREUPLOAD.cfg | 1 | ||||
| -rw-r--r-- | tools/csuite_test/Android.bp | 16 | ||||
| -rw-r--r-- | tools/csuite_test/csuite_test.go | 119 | ||||
| -rw-r--r-- | tools/csuite_test/csuite_test_test.go | 235 | ||||
| -rw-r--r-- | tools/csuite_test/go.mod | 14 |
5 files changed, 385 insertions, 0 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 948fa79..91c7914 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -1,5 +1,6 @@ [Builtin Hooks] bpfmt = true +gofmt = true google_java_format = true pylint = true xmllint = true diff --git a/tools/csuite_test/Android.bp b/tools/csuite_test/Android.bp new file mode 100644 index 0000000..e44d78c --- /dev/null +++ b/tools/csuite_test/Android.bp @@ -0,0 +1,16 @@ +bootstrap_go_package { + name: "soong-csuite", + pkgPath: "android/soong/csuite", + deps: [ + "blueprint", + "soong-android", + "soong-java", + ], + srcs: [ + "csuite_test.go", + ], + testSrcs: [ + "csuite_test_test.go", + ], + pluginFor: ["soong_build"], +} diff --git a/tools/csuite_test/csuite_test.go b/tools/csuite_test/csuite_test.go new file mode 100644 index 0000000..b34226a --- /dev/null +++ b/tools/csuite_test/csuite_test.go @@ -0,0 +1,119 @@ +// Copyright 2020 Google Inc. All rights reserved. +// +// 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 csuite + +import ( + "android/soong/android" + "android/soong/java" + "strings" +) + +var ( + pctx = android.NewPackageContext("android/soong/csuite") +) + +func init() { + android.RegisterModuleType("csuite_test", CSuiteTestFactory) +} + +type csuiteTestProperties struct { + // Local path to a module template xml file. + // The content of the template will be used to generate test modules at runtime. + Test_config_template *string `android:"path"` +} + +type CSuiteTest struct { + // Java TestHost. + java.TestHost + + // C-Suite test properties struct. + csuiteTestProperties csuiteTestProperties + + // Local path to a xml config file to be included in the test plan. + Test_plan_include *string `android:"path"` +} + +func (cSuiteTest *CSuiteTest) generateTestConfigTemplate(rule *android.RuleBuilder, ctx android.ModuleContext) android.ModuleGenPath { + if cSuiteTest.csuiteTestProperties.Test_config_template == nil { + ctx.ModuleErrorf(`'test_config_template' is missing.`) + } + inputPath := android.PathForModuleSrc(ctx, *cSuiteTest.csuiteTestProperties.Test_config_template) + genPath := android.PathForModuleGen(ctx, planConfigDirName, ctx.ModuleName()+configTemplateFileExtension) + rule.Command().Textf("cp").Input(inputPath).Output(genPath) + return genPath +} + +func (cSuiteTest *CSuiteTest) generatePlanConfig(templatePathString string, ctx android.ModuleContext) android.ModuleGenPath { + planName := ctx.ModuleName() + genPath := android.PathForModuleGen(ctx, planConfigDirName, planName+planFileExtension) + content := strings.Replace(planTemplateContent, "{planName}", planName, -1) + content = strings.Replace(content, "{templatePath}", templatePathString, -1) + android.WriteFileRule(ctx, genPath, content) + return genPath +} + +func (cSuiteTest *CSuiteTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { + rule := android.NewRuleBuilder(pctx, ctx) + + configTemplateOutputPath := cSuiteTest.generateTestConfigTemplate(rule, ctx) + cSuiteTest.AddExtraResource(configTemplateOutputPath) + + planOutputFile := cSuiteTest.generatePlanConfig(configTemplateOutputPath.Rel(), ctx) + cSuiteTest.AddExtraResource(planOutputFile) + + rule.Build("CSuite", "generate C-Suite config files") + cSuiteTest.TestHost.GenerateAndroidBuildActions(ctx) +} + +func CSuiteTestFactory() android.Module { + module := &CSuiteTest{} + module.AddProperties(&module.csuiteTestProperties) + installable := true + autoGenConfig := false + java.InitTestHost(&module.TestHost, &installable, []string{"csuite"}, &autoGenConfig) + + java.InitJavaModuleMultiTargets(module, android.HostSupported) + + return module +} + +const ( + planConfigDirName = `config` + configTemplateFileExtension = `.xml.template` + planFileExtension = `.xml` + planTemplateContent = `<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2020 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. +--> +<configuration> + <test class="com.android.csuite.config.ModuleGenerator"> + <option name="template" value="{templatePath}" /> + </test> + <include name="csuite-base" /> + <option name="plan" value="{planName}" /> +</configuration> +` +) diff --git a/tools/csuite_test/csuite_test_test.go b/tools/csuite_test/csuite_test_test.go new file mode 100644 index 0000000..0223da1 --- /dev/null +++ b/tools/csuite_test/csuite_test_test.go @@ -0,0 +1,235 @@ +// Copyright 2020 Google Inc. All rights reserved. +// +// 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 csuite + +import ( + "android/soong/android" + "io/ioutil" + "os" + "strings" + "testing" +) + +var buildDir string + +func TestValidBpDoesNotThrowError(t *testing.T) { + ctx, config := createContextAndConfig(t, ` + csuite_test { + name: "plan_name", + test_config_template: "test_config.xml.template" + } + `) + + _, errs := ctx.PrepareBuildActions(config) + + android.FailIfErrored(t, errs) +} + +func TestBpContainsTestHostPropsThrowsError(t *testing.T) { + ctx, _ := createContextAndConfig(t, ` + csuite_test { + name: "plan_name", + test_config_template: "test_config.xml.template", + data_native_bins: "bin" + } + `) + + _, errs := ctx.ParseBlueprintsFiles("Android.bp") + + android.FailIfNoMatchingErrors(t, `unrecognized property`, errs) +} + +func TestBpContainsManifestThrowsError(t *testing.T) { + ctx, _ := createContextAndConfig(t, ` + csuite_test { + name: "plan_name", + test_config_template: "test_config.xml.template", + test_config: "AndroidTest.xml" + } + `) + + _, errs := ctx.ParseBlueprintsFiles("Android.bp") + + android.FailIfNoMatchingErrors(t, `unrecognized property`, errs) +} + +func TestBpMissingNameThrowsError(t *testing.T) { + ctx, _ := createContextAndConfig(t, ` + csuite_test { + test_config_template: "test_config.xml.template" + } + `) + + _, errs := ctx.ParseBlueprintsFiles("Android.bp") + + android.FailIfNoMatchingErrors(t, `'name' is missing`, errs) +} + +func TestBpMissingTemplatePathThrowsError(t *testing.T) { + ctx, config := createContextAndConfig(t, ` + csuite_test { + name: "plan_name", + } + `) + + ctx.ParseBlueprintsFiles("Android.bp") + _, errs := ctx.PrepareBuildActions(config) + + android.FailIfNoMatchingErrors(t, `'test_config_template' is missing`, errs) +} + +func TestGeneratedTestPlanContainsPlanName(t *testing.T) { + ctx, config := createContextAndConfig(t, ` + csuite_test { + name: "plan_name", + test_config_template: "test_config.xml.template" + } + `) + + _, parsingErrs := ctx.ParseBlueprintsFiles("Android.bp") + _, buildErrs := ctx.PrepareBuildActions(config) + + android.FailIfErrored(t, parsingErrs) + android.FailIfErrored(t, buildErrs) + module := ctx.ModuleForTests("plan_name", android.BuildOs.String()+"_common") + content := android.ContentFromFileRuleForTests(t, module.Output("config/plan_name.xml")) + if !strings.Contains(content, "plan_name") { + t.Errorf("The plan name is missing from the generated plan: %s", content) + } +} + +func TestGeneratedTestPlanContainsTemplatePath(t *testing.T) { + ctx, config := createContextAndConfig(t, ` + csuite_test { + name: "plan_name", + test_config_template: "test_config.xml.template" + } + `) + + _, parsingErrs := ctx.ParseBlueprintsFiles("Android.bp") + _, buildErrs := ctx.PrepareBuildActions(config) + + android.FailIfErrored(t, parsingErrs) + android.FailIfErrored(t, buildErrs) + module := ctx.ModuleForTests("plan_name", android.BuildOs.String()+"_common") + content := android.ContentFromFileRuleForTests(t, module.Output("config/plan_name.xml")) + if !strings.Contains(content, "config/plan_name.xml.template") { + t.Errorf("The template path is missing from the generated plan: %s", content) + } +} + +func TestTemplateFileCopyRuleExists(t *testing.T) { + ctx, config := createContextAndConfig(t, ` + csuite_test { + name: "plan_name", + test_config_template: "test_config.xml.template" + } + `) + + _, parsingErrs := ctx.ParseBlueprintsFiles("Android.bp") + _, buildErrs := ctx.PrepareBuildActions(config) + + android.FailIfErrored(t, parsingErrs) + android.FailIfErrored(t, buildErrs) + params := ctx.ModuleForTests("plan_name", android.BuildOs.String()+"_common").Rule("CSuite") + assertPathsContains(t, getAllInputPaths(params), "test_config.xml.template") + assertWritablePathsContainsRel(t, getAllOutputPaths(params), "config/plan_name.xml.template") + if !strings.HasPrefix(params.RuleParams.Command, "cp") { + t.Errorf("'cp' command is missing.") + } +} + +func TestMain(m *testing.M) { + run := func() int { + setUp() + defer tearDown() + + return m.Run() + } + + os.Exit(run()) +} + +func assertPathsContains(t *testing.T, paths android.Paths, path string) { + for _, p := range paths { + if p.String() == path { + return + } + } + t.Errorf("Cannot find expected path %s", path) +} + +func assertWritablePathsContainsRel(t *testing.T, paths android.WritablePaths, relPath string) { + for _, path := range paths { + if path.Rel() == relPath { + return + } + } + t.Errorf("Cannot find expected relative path %s", relPath) +} + +func getAllOutputPaths(params android.TestingBuildParams) android.WritablePaths { + var paths []android.WritablePath + if params.Output != nil { + paths = append(paths, params.Output) + } + if params.ImplicitOutput != nil { + paths = append(paths, params.ImplicitOutput) + } + if params.SymlinkOutput != nil { + paths = append(paths, params.SymlinkOutput) + } + paths = append(paths, params.Outputs...) + paths = append(paths, params.ImplicitOutputs...) + paths = append(paths, params.SymlinkOutputs...) + + return paths +} + +func getAllInputPaths(params android.TestingBuildParams) android.Paths { + var paths []android.Path + if params.Input != nil { + paths = append(paths, params.Input) + } + if params.Implicit != nil { + paths = append(paths, params.Implicit) + } + paths = append(paths, params.Inputs...) + paths = append(paths, params.Implicits...) + + return paths +} + +func setUp() { + var err error + buildDir, err = ioutil.TempDir("", "soong_csuite_test") + if err != nil { + panic(err) + } +} + +func tearDown() { + os.RemoveAll(buildDir) +} + +func createContextAndConfig(t *testing.T, bp string) (*android.TestContext, android.Config) { + t.Helper() + config := android.TestArchConfig(buildDir, nil, bp, nil) + ctx := android.NewTestArchContext(config) + ctx.RegisterModuleType("csuite_test", CSuiteTestFactory) + ctx.Register() + + return ctx, config +} diff --git a/tools/csuite_test/go.mod b/tools/csuite_test/go.mod new file mode 100644 index 0000000..a373cd1 --- /dev/null +++ b/tools/csuite_test/go.mod @@ -0,0 +1,14 @@ +module android/soong/csuite + +require ( + android/soong v0.0.0 + github.com/google/blueprint v0.0.0 +) + +replace android/soong v0.0.0 => ../../../../../build/soong + +replace github.com/golang/protobuf v0.0.0 => ../../../../../external/golang-protobuf + +replace github.com/google/blueprint v0.0.0 => ../../../../../build/blueprint + +go 1.13
\ No newline at end of file |
