platform_build_soong/apex/bp2build_test.go
Jingwen Chen 2d37b641c5 Populate apexBundle#filesInfo using bazel info.
This CL adds a few things:

1) Populate the filesInfo struct with cquery'd information from an
apex's ApexMkInfo provider. This filesInfo is then used in
apex/androidmk.go to generate Make modules (soong_cc_rust_prebuilt.mk),
which are then used in packaging to generate zip files of symbols in $PRODUCT_OUT.
2) Make a list of dicts of primitives JSON-encodable.
3) Tests.

Bug: 271423316
Bug: 271423062
Test: presubmits
Change-Id: Iaa34f51044de310510e580d9cf1fe60bbef801c1
2023-03-16 18:09:27 +00:00

461 lines
16 KiB
Go

// Copyright 2022 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 apex
import (
"android/soong/android"
"android/soong/bazel/cquery"
"strings"
"testing"
)
func TestApexImageInMixedBuilds(t *testing.T) {
bp := `
apex_key{
name: "foo_key",
}
apex {
name: "foo",
key: "foo_key",
updatable: true,
min_sdk_version: "31",
file_contexts: ":myapex-file_contexts",
bazel_module: { label: "//:foo" },
}`
outputBaseDir := "out/bazel"
result := android.GroupFixturePreparers(
prepareForApexTest,
android.FixtureModifyConfig(func(config android.Config) {
config.BazelContext = android.MockBazelContext{
OutputBaseDir: outputBaseDir,
LabelToApexInfo: map[string]cquery.ApexInfo{
"//:foo": cquery.ApexInfo{
// ApexInfo Starlark provider.
SignedOutput: "signed_out.apex",
SignedCompressedOutput: "signed_out.capex",
UnsignedOutput: "unsigned_out.apex",
BundleKeyInfo: []string{"public_key", "private_key"},
ContainerKeyInfo: []string{"container_cert", "container_private"},
SymbolsUsedByApex: "foo_using.txt",
JavaSymbolsUsedByApex: "foo_using.xml",
BundleFile: "apex_bundle.zip",
InstalledFiles: "installed-files.txt",
RequiresLibs: []string{"//path/c:c", "//path/d:d"},
// unused
PackageName: "pkg_name",
ProvidesLibs: []string{"a", "b"},
// ApexMkInfo Starlark provider
PayloadFilesInfo: []map[string]string{
{
"built_file": "bazel-out/adbd",
"install_dir": "bin",
"class": "nativeExecutable",
"make_module_name": "adbd",
"basename": "adbd",
"package": "foo",
},
},
MakeModulesToInstall: []string{"c"}, // d deliberately omitted
},
},
}
}),
).RunTestWithBp(t, bp)
m := result.ModuleForTests("foo", "android_common_foo_image").Module()
ab, ok := m.(*apexBundle)
if !ok {
t.Fatalf("Expected module to be an apexBundle, was not")
}
// TODO: refactor to android.AssertStringEquals
if w, g := "out/bazel/execroot/__main__/public_key", ab.publicKeyFile.String(); w != g {
t.Errorf("Expected public key %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/private_key", ab.privateKeyFile.String(); w != g {
t.Errorf("Expected private key %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/container_cert", ab.containerCertificateFile.String(); w != g {
t.Errorf("Expected public container key %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/container_private", ab.containerPrivateKeyFile.String(); w != g {
t.Errorf("Expected private container key %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/signed_out.apex", ab.outputFile.String(); w != g {
t.Errorf("Expected output file %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/foo_using.txt", ab.nativeApisUsedByModuleFile.String(); w != g {
t.Errorf("Expected output file %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/foo_using.xml", ab.javaApisUsedByModuleFile.String(); w != g {
t.Errorf("Expected output file %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/installed-files.txt", ab.installedFilesFile.String(); w != g {
t.Errorf("Expected installed-files.txt %q, got %q", w, g)
}
mkData := android.AndroidMkDataForTest(t, result.TestContext, m)
var builder strings.Builder
mkData.Custom(&builder, "foo", "BAZEL_TARGET_", "", mkData)
data := builder.String()
if w := "ALL_MODULES.$(my_register_name).BUNDLE := out/bazel/execroot/__main__/apex_bundle.zip"; !strings.Contains(data, w) {
t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
}
if w := "$(call dist-for-goals,checkbuild,out/bazel/execroot/__main__/installed-files.txt:foo-installed-files.txt)"; !strings.Contains(data, w) {
t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
}
// make modules to be installed to system
if len(ab.makeModulesToInstall) != 1 && ab.makeModulesToInstall[0] != "c" {
t.Errorf("Expected makeModulesToInstall slice to only contain 'c', got %q", ab.makeModulesToInstall)
}
if w := "LOCAL_REQUIRED_MODULES := adbd.foo c"; !strings.Contains(data, w) {
t.Errorf("Expected %q in androidmk data, but did not find it in %q", w, data)
}
}
func TestApexImageCreatesFilesInfoForMake(t *testing.T) {
bp := `
apex_key{
name: "foo_key",
}
apex {
name: "foo",
key: "foo_key",
updatable: true,
min_sdk_version: "31",
file_contexts: ":myapex-file_contexts",
bazel_module: { label: "//:foo" },
}`
outputBaseDir := "out/bazel"
result := android.GroupFixturePreparers(
prepareForApexTest,
android.FixtureModifyConfig(func(config android.Config) {
config.BazelContext = android.MockBazelContext{
OutputBaseDir: outputBaseDir,
LabelToApexInfo: map[string]cquery.ApexInfo{
"//:foo": {
// ApexInfo Starlark provider. Necessary for the test.
SignedOutput: "signed_out.apex",
BundleKeyInfo: []string{"public_key", "private_key"},
ContainerKeyInfo: []string{"container_cert", "container_private"},
// ApexMkInfo Starlark provider
PayloadFilesInfo: []map[string]string{
{
"arch": "arm64",
"basename": "libcrypto.so",
"built_file": "bazel-out/64/libcrypto.so",
"class": "nativeSharedLib",
"install_dir": "lib64",
"make_module_name": "libcrypto",
"package": "foo/bar",
"unstripped_built_file": "bazel-out/64/unstripped_libcrypto.so",
},
{
"arch": "arm",
"basename": "libcrypto.so",
"built_file": "bazel-out/32/libcrypto.so",
"class": "nativeSharedLib",
"install_dir": "lib",
"make_module_name": "libcrypto",
"package": "foo/bar",
},
{
"arch": "arm64",
"basename": "adbd",
"built_file": "bazel-out/adbd",
"class": "nativeExecutable",
"install_dir": "bin",
"make_module_name": "adbd",
"package": "foo",
},
},
},
},
}
}),
).RunTestWithBp(t, bp)
m := result.ModuleForTests("foo", "android_common_foo_image").Module()
ab, ok := m.(*apexBundle)
if !ok {
t.Fatalf("Expected module to be an apexBundle, was not")
}
expectedFilesInfo := []apexFile{
{
androidMkModuleName: "libcrypto",
builtFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/64/libcrypto.so"),
class: nativeSharedLib,
customStem: "libcrypto.so",
installDir: "lib64",
moduleDir: "foo/bar",
arch: "arm64",
unstrippedBuiltFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/64/unstripped_libcrypto.so"),
},
{
androidMkModuleName: "libcrypto",
builtFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/32/libcrypto.so"),
class: nativeSharedLib,
customStem: "libcrypto.so",
installDir: "lib",
moduleDir: "foo/bar",
arch: "arm",
},
{
androidMkModuleName: "adbd",
builtFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/adbd"),
class: nativeExecutable,
customStem: "adbd",
installDir: "bin",
moduleDir: "foo",
arch: "arm64",
},
}
if len(ab.filesInfo) != len(expectedFilesInfo) {
t.Errorf("Expected %d entries in ab.filesInfo, but got %d", len(ab.filesInfo), len(expectedFilesInfo))
}
for idx, f := range ab.filesInfo {
expected := expectedFilesInfo[idx]
android.AssertSame(t, "different class", expected.class, f.class)
android.AssertStringEquals(t, "different built file", expected.builtFile.String(), f.builtFile.String())
android.AssertStringEquals(t, "different custom stem", expected.customStem, f.customStem)
android.AssertStringEquals(t, "different install dir", expected.installDir, f.installDir)
android.AssertStringEquals(t, "different make module name", expected.androidMkModuleName, f.androidMkModuleName)
android.AssertStringEquals(t, "different moduleDir", expected.moduleDir, f.moduleDir)
android.AssertStringEquals(t, "different arch", expected.arch, f.arch)
if expected.unstrippedBuiltFile != nil {
if f.unstrippedBuiltFile == nil {
t.Errorf("expected an unstripped built file path.")
}
android.AssertStringEquals(t, "different unstripped built file", expected.unstrippedBuiltFile.String(), f.unstrippedBuiltFile.String())
}
}
}
func TestCompressedApexImageInMixedBuilds(t *testing.T) {
bp := `
apex_key{
name: "foo_key",
}
apex {
name: "foo",
key: "foo_key",
updatable: true,
min_sdk_version: "31",
file_contexts: ":myapex-file_contexts",
bazel_module: { label: "//:foo" },
test_only_force_compression: true, // force compression
}`
outputBaseDir := "out/bazel"
result := android.GroupFixturePreparers(
prepareForApexTest,
android.FixtureModifyConfig(func(config android.Config) {
config.BazelContext = android.MockBazelContext{
OutputBaseDir: outputBaseDir,
LabelToApexInfo: map[string]cquery.ApexInfo{
"//:foo": cquery.ApexInfo{
SignedOutput: "signed_out.apex",
SignedCompressedOutput: "signed_out.capex",
BundleKeyInfo: []string{"public_key", "private_key"},
ContainerKeyInfo: []string{"container_cert", "container_private"},
},
},
}
}),
).RunTestWithBp(t, bp)
m := result.ModuleForTests("foo", "android_common_foo_image").Module()
ab, ok := m.(*apexBundle)
if !ok {
t.Fatalf("Expected module to be an apexBundle, was not")
}
if w, g := "out/bazel/execroot/__main__/signed_out.capex", ab.outputFile.String(); w != g {
t.Errorf("Expected output file to be compressed apex %q, got %q", w, g)
}
mkData := android.AndroidMkDataForTest(t, result.TestContext, m)
var builder strings.Builder
mkData.Custom(&builder, "foo", "BAZEL_TARGET_", "", mkData)
data := builder.String()
expectedAndroidMk := []string{
"LOCAL_PREBUILT_MODULE_FILE := out/bazel/execroot/__main__/signed_out.capex",
// Check that the source install file is the capex. The dest is not important.
"LOCAL_SOONG_INSTALL_PAIRS := out/bazel/execroot/__main__/signed_out.capex:",
}
for _, androidMk := range expectedAndroidMk {
if !strings.Contains(data, androidMk) {
t.Errorf("Expected %q in androidmk data, but did not find %q", androidMk, data)
}
}
}
func TestOverrideApexImageInMixedBuilds(t *testing.T) {
bp := `
apex_key{
name: "foo_key",
}
apex_key{
name: "override_foo_key",
}
apex {
name: "foo",
key: "foo_key",
updatable: true,
min_sdk_version: "31",
package_name: "pkg_name",
file_contexts: ":myapex-file_contexts",
bazel_module: { label: "//:foo" },
}
override_apex {
name: "override_foo",
key: "override_foo_key",
package_name: "override_pkg_name",
base: "foo",
bazel_module: { label: "//:override_foo" },
}
`
outputBaseDir := "out/bazel"
result := android.GroupFixturePreparers(
prepareForApexTest,
android.FixtureModifyConfig(func(config android.Config) {
config.BazelContext = android.MockBazelContext{
OutputBaseDir: outputBaseDir,
LabelToApexInfo: map[string]cquery.ApexInfo{
"//:foo": cquery.ApexInfo{
// ApexInfo Starlark provider
SignedOutput: "signed_out.apex",
UnsignedOutput: "unsigned_out.apex",
BundleKeyInfo: []string{"public_key", "private_key"},
ContainerKeyInfo: []string{"container_cert", "container_private"},
SymbolsUsedByApex: "foo_using.txt",
JavaSymbolsUsedByApex: "foo_using.xml",
BundleFile: "apex_bundle.zip",
InstalledFiles: "installed-files.txt",
RequiresLibs: []string{"//path/c:c", "//path/d:d"},
// unused
PackageName: "pkg_name",
ProvidesLibs: []string{"a", "b"},
// ApexMkInfo Starlark provider
MakeModulesToInstall: []string{"c"}, // d deliberately omitted
},
"//:override_foo": cquery.ApexInfo{
// ApexInfo Starlark provider
SignedOutput: "override_signed_out.apex",
UnsignedOutput: "override_unsigned_out.apex",
BundleKeyInfo: []string{"override_public_key", "override_private_key"},
ContainerKeyInfo: []string{"override_container_cert", "override_container_private"},
SymbolsUsedByApex: "override_foo_using.txt",
JavaSymbolsUsedByApex: "override_foo_using.xml",
BundleFile: "override_apex_bundle.zip",
InstalledFiles: "override_installed-files.txt",
RequiresLibs: []string{"//path/c:c", "//path/d:d"},
// unused
PackageName: "override_pkg_name",
ProvidesLibs: []string{"a", "b"},
// ApexMkInfo Starlark provider
MakeModulesToInstall: []string{"c"}, // d deliberately omitted
},
},
}
}),
).RunTestWithBp(t, bp)
m := result.ModuleForTests("foo", "android_common_override_foo_foo_image").Module()
ab, ok := m.(*apexBundle)
if !ok {
t.Fatalf("Expected module to be an apexBundle, was not")
}
if w, g := "out/bazel/execroot/__main__/override_public_key", ab.publicKeyFile.String(); w != g {
t.Errorf("Expected public key %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/override_private_key", ab.privateKeyFile.String(); w != g {
t.Errorf("Expected private key %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/override_container_cert", ab.containerCertificateFile.String(); w != g {
t.Errorf("Expected public container key %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/override_container_private", ab.containerPrivateKeyFile.String(); w != g {
t.Errorf("Expected private container key %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/override_signed_out.apex", ab.outputFile.String(); w != g {
t.Errorf("Expected output file %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/override_foo_using.txt", ab.nativeApisUsedByModuleFile.String(); w != g {
t.Errorf("Expected output file %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/override_foo_using.xml", ab.javaApisUsedByModuleFile.String(); w != g {
t.Errorf("Expected output file %q, got %q", w, g)
}
if w, g := "out/bazel/execroot/__main__/override_installed-files.txt", ab.installedFilesFile.String(); w != g {
t.Errorf("Expected installed-files.txt %q, got %q", w, g)
}
mkData := android.AndroidMkDataForTest(t, result.TestContext, m)
var builder strings.Builder
mkData.Custom(&builder, "override_foo", "BAZEL_TARGET_", "", mkData)
data := builder.String()
if w := "ALL_MODULES.$(my_register_name).BUNDLE := out/bazel/execroot/__main__/override_apex_bundle.zip"; !strings.Contains(data, w) {
t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
}
if w := "$(call dist-for-goals,checkbuild,out/bazel/execroot/__main__/override_installed-files.txt:override_foo-installed-files.txt)"; !strings.Contains(data, w) {
t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
}
// make modules to be installed to system
if len(ab.makeModulesToInstall) != 1 && ab.makeModulesToInstall[0] != "c" {
t.Errorf("Expected makeModulestoInstall slice to only contain 'c', got %q", ab.makeModulesToInstall)
}
if w := "LOCAL_REQUIRED_MODULES := c"; !strings.Contains(data, w) {
t.Errorf("Expected %q in androidmk data, but did not find it in %q", w, data)
}
}