// Copyright 2019 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 sdk import ( "log" "os" "runtime" "testing" "android/soong/android" "android/soong/java" "github.com/google/blueprint/proptools" ) // Needed in an _test.go file in this package to ensure tests run correctly, particularly in IDE. func TestMain(m *testing.M) { if runtime.GOOS != "linux" { // b/145598135 - Generating host snapshots for anything other than linux is not supported. log.Printf("Skipping as sdk snapshot generation is only supported on linux not %s", runtime.GOOS) os.Exit(0) } os.Exit(m.Run()) } func TestDepNotInRequiredSdks(t *testing.T) { testSdkError(t, `module "myjavalib".*depends on "otherlib".*that isn't part of the required SDKs:.*`, ` sdk { name: "mysdk", java_header_libs: ["sdkmember"], } sdk_snapshot { name: "mysdk@1", java_header_libs: ["sdkmember_mysdk_1"], } java_import { name: "sdkmember", prefer: false, host_supported: true, } java_import { name: "sdkmember_mysdk_1", sdk_member_name: "sdkmember", host_supported: true, } java_library { name: "myjavalib", srcs: ["Test.java"], libs: [ "sdkmember", "otherlib", ], system_modules: "none", sdk_version: "none", compile_dex: true, host_supported: true, apex_available: ["myapex"], } // this lib is no in mysdk java_library { name: "otherlib", srcs: ["Test.java"], system_modules: "none", sdk_version: "none", compile_dex: true, host_supported: true, } apex { name: "myapex", java_libs: ["myjavalib"], uses_sdks: ["mysdk@1"], key: "myapex.key", certificate: ":myapex.cert", } `) } // Ensure that prebuilt modules have the same effective visibility as the source // modules. func TestSnapshotVisibility(t *testing.T) { packageBp := ` package { default_visibility: ["//other/foo"], } sdk { name: "mysdk", visibility: [ "//other/foo", // This short form will be replaced with //package:__subpackages__ in the // generated sdk_snapshot. ":__subpackages__", ], prebuilt_visibility: [ "//prebuilts/mysdk", ], java_header_libs: [ "myjavalib", "mypublicjavalib", "mydefaultedjavalib", "myprivatejavalib", ], } java_library { name: "myjavalib", // Uses package default visibility srcs: ["Test.java"], system_modules: "none", sdk_version: "none", } java_defaults { name: "java-defaults", visibility: ["//other/bar"], } java_library { name: "mypublicjavalib", defaults: ["java-defaults"], visibility: ["//visibility:public"], srcs: ["Test.java"], system_modules: "none", sdk_version: "none", } java_defaults { name: "myjavadefaults", visibility: ["//other/bar"], } java_library { name: "mydefaultedjavalib", defaults: ["myjavadefaults"], srcs: ["Test.java"], system_modules: "none", sdk_version: "none", } java_library { name: "myprivatejavalib", srcs: ["Test.java"], visibility: ["//visibility:private"], system_modules: "none", sdk_version: "none", } ` result := testSdkWithFs(t, ``, map[string][]byte{ "package/Test.java": nil, "package/Android.bp": []byte(packageBp), }) CheckSnapshot(t, result, "mysdk", "package", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. java_import { name: "mysdk_myjavalib@current", sdk_member_name: "myjavalib", visibility: [ "//other/foo", "//package", "//prebuilts/mysdk", ], apex_available: ["//apex_available:platform"], jars: ["java/myjavalib.jar"], } java_import { name: "myjavalib", prefer: false, visibility: [ "//other/foo", "//package", "//prebuilts/mysdk", ], apex_available: ["//apex_available:platform"], jars: ["java/myjavalib.jar"], } java_import { name: "mysdk_mypublicjavalib@current", sdk_member_name: "mypublicjavalib", visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], jars: ["java/mypublicjavalib.jar"], } java_import { name: "mypublicjavalib", prefer: false, visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], jars: ["java/mypublicjavalib.jar"], } java_import { name: "mysdk_mydefaultedjavalib@current", sdk_member_name: "mydefaultedjavalib", visibility: [ "//other/bar", "//package", "//prebuilts/mysdk", ], apex_available: ["//apex_available:platform"], jars: ["java/mydefaultedjavalib.jar"], } java_import { name: "mydefaultedjavalib", prefer: false, visibility: [ "//other/bar", "//package", "//prebuilts/mysdk", ], apex_available: ["//apex_available:platform"], jars: ["java/mydefaultedjavalib.jar"], } java_import { name: "mysdk_myprivatejavalib@current", sdk_member_name: "myprivatejavalib", visibility: [ "//package", "//prebuilts/mysdk", ], apex_available: ["//apex_available:platform"], jars: ["java/myprivatejavalib.jar"], } java_import { name: "myprivatejavalib", prefer: false, visibility: [ "//package", "//prebuilts/mysdk", ], apex_available: ["//apex_available:platform"], jars: ["java/myprivatejavalib.jar"], } sdk_snapshot { name: "mysdk@current", visibility: [ "//other/foo", "//package:__subpackages__", ], java_header_libs: [ "mysdk_myjavalib@current", "mysdk_mypublicjavalib@current", "mysdk_mydefaultedjavalib@current", "mysdk_myprivatejavalib@current", ], } `)) } func TestPrebuiltVisibilityProperty_IsValidated(t *testing.T) { testSdkError(t, `prebuilt_visibility: cannot mix "//visibility:private" with any other visibility rules`, ` sdk { name: "mysdk", prebuilt_visibility: [ "//foo", "//visibility:private", ], } `) } func TestPrebuiltVisibilityProperty_AddPrivate(t *testing.T) { testSdkError(t, `prebuilt_visibility: "//visibility:private" does not widen the visibility`, ` sdk { name: "mysdk", prebuilt_visibility: [ "//visibility:private", ], java_header_libs: [ "myjavalib", ], } java_library { name: "myjavalib", // Uses package default visibility srcs: ["Test.java"], system_modules: "none", sdk_version: "none", } `) } func TestSdkInstall(t *testing.T) { sdk := ` sdk { name: "mysdk", } ` result := testSdkWithFs(t, sdk, nil) CheckSnapshot(t, result, "mysdk", "", checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`)) } type EmbeddedPropertiesStruct struct { S_Embedded_Common string `android:"arch_variant"` S_Embedded_Different string `android:"arch_variant"` } type testPropertiesStruct struct { name string private string Public_Kept string `sdk:"keep"` S_Common string S_Different string `android:"arch_variant"` A_Common []string A_Different []string `android:"arch_variant"` F_Common *bool F_Different *bool `android:"arch_variant"` EmbeddedPropertiesStruct } func (p *testPropertiesStruct) optimizableProperties() interface{} { return p } func (p *testPropertiesStruct) String() string { return p.name } var _ propertiesContainer = (*testPropertiesStruct)(nil) func TestCommonValueOptimization(t *testing.T) { common := &testPropertiesStruct{name: "common"} structs := []propertiesContainer{ &testPropertiesStruct{ name: "struct-0", private: "common", Public_Kept: "common", S_Common: "common", S_Different: "upper", A_Common: []string{"first", "second"}, A_Different: []string{"alpha", "beta"}, F_Common: proptools.BoolPtr(false), F_Different: proptools.BoolPtr(false), EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{ S_Embedded_Common: "embedded_common", S_Embedded_Different: "embedded_upper", }, }, &testPropertiesStruct{ name: "struct-1", private: "common", Public_Kept: "common", S_Common: "common", S_Different: "lower", A_Common: []string{"first", "second"}, A_Different: []string{"alpha", "delta"}, F_Common: proptools.BoolPtr(false), F_Different: proptools.BoolPtr(true), EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{ S_Embedded_Common: "embedded_common", S_Embedded_Different: "embedded_lower", }, }, } extractor := newCommonValueExtractor(common) err := extractor.extractCommonProperties(common, structs) android.AssertDeepEquals(t, "unexpected error", nil, err) android.AssertDeepEquals(t, "common properties not correct", &testPropertiesStruct{ name: "common", private: "", Public_Kept: "", S_Common: "common", S_Different: "", A_Common: []string{"first", "second"}, A_Different: []string(nil), F_Common: proptools.BoolPtr(false), F_Different: nil, EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{ S_Embedded_Common: "embedded_common", S_Embedded_Different: "", }, }, common) android.AssertDeepEquals(t, "updated properties[0] not correct", &testPropertiesStruct{ name: "struct-0", private: "common", Public_Kept: "common", S_Common: "", S_Different: "upper", A_Common: nil, A_Different: []string{"alpha", "beta"}, F_Common: nil, F_Different: proptools.BoolPtr(false), EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{ S_Embedded_Common: "", S_Embedded_Different: "embedded_upper", }, }, structs[0]) android.AssertDeepEquals(t, "updated properties[1] not correct", &testPropertiesStruct{ name: "struct-1", private: "common", Public_Kept: "common", S_Common: "", S_Different: "lower", A_Common: nil, A_Different: []string{"alpha", "delta"}, F_Common: nil, F_Different: proptools.BoolPtr(true), EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{ S_Embedded_Common: "", S_Embedded_Different: "embedded_lower", }, }, structs[1]) } func TestCommonValueOptimization_InvalidArchSpecificVariants(t *testing.T) { common := &testPropertiesStruct{name: "common"} structs := []propertiesContainer{ &testPropertiesStruct{ name: "struct-0", S_Common: "should-be-but-is-not-common0", }, &testPropertiesStruct{ name: "struct-1", S_Common: "should-be-but-is-not-common1", }, } extractor := newCommonValueExtractor(common) err := extractor.extractCommonProperties(common, structs) android.AssertErrorMessageEquals(t, "unexpected error", `field "S_Common" is not tagged as "arch_variant" but has arch specific properties: "struct-0" has value "should-be-but-is-not-common0" "struct-1" has value "should-be-but-is-not-common1"`, err) } // Ensure that sdk snapshot related environment variables work correctly. func TestSnapshot_EnvConfiguration(t *testing.T) { bp := ` sdk { name: "mysdk", java_header_libs: ["myjavalib"], } java_library { name: "myjavalib", srcs: ["Test.java"], system_modules: "none", sdk_version: "none", compile_dex: true, host_supported: true, } ` preparer := android.GroupFixturePreparers( prepareForSdkTestWithJava, android.FixtureWithRootAndroidBp(bp), ) checkZipFile := func(t *testing.T, result *android.TestResult, expected string) { zipRule := result.ModuleForTests("mysdk", "common_os").Rule("SnapshotZipFiles") android.AssertStringEquals(t, "snapshot zip file", expected, zipRule.Output.String()) } t.Run("no env variables", func(t *testing.T) { result := preparer.RunTest(t) checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-current.zip") CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. java_import { name: "mysdk_myjavalib@current", sdk_member_name: "myjavalib", visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], jars: ["java/myjavalib.jar"], } java_import { name: "myjavalib", prefer: false, visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], jars: ["java/myjavalib.jar"], } sdk_snapshot { name: "mysdk@current", visibility: ["//visibility:public"], java_header_libs: ["mysdk_myjavalib@current"], } `), ) }) t.Run("SOONG_SDK_SNAPSHOT_PREFER=true", func(t *testing.T) { result := android.GroupFixturePreparers( preparer, android.FixtureMergeEnv(map[string]string{ "SOONG_SDK_SNAPSHOT_PREFER": "true", }), ).RunTest(t) checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-current.zip") CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. java_import { name: "mysdk_myjavalib@current", sdk_member_name: "myjavalib", visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], jars: ["java/myjavalib.jar"], } java_import { name: "myjavalib", prefer: true, visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], jars: ["java/myjavalib.jar"], } sdk_snapshot { name: "mysdk@current", visibility: ["//visibility:public"], java_header_libs: ["mysdk_myjavalib@current"], } `), ) }) t.Run("SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR=module:build_from_source", func(t *testing.T) { result := android.GroupFixturePreparers( preparer, android.FixtureMergeEnv(map[string]string{ "SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR": "module:build_from_source", }), ).RunTest(t) checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-current.zip") CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. java_import { name: "mysdk_myjavalib@current", sdk_member_name: "myjavalib", visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], jars: ["java/myjavalib.jar"], } java_import { name: "myjavalib", prefer: false, use_source_config_var: { config_namespace: "module", var_name: "build_from_source", }, visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], jars: ["java/myjavalib.jar"], } sdk_snapshot { name: "mysdk@current", visibility: ["//visibility:public"], java_header_libs: ["mysdk_myjavalib@current"], } `), ) }) t.Run("SOONG_SDK_SNAPSHOT_VERSION=unversioned", func(t *testing.T) { result := android.GroupFixturePreparers( preparer, android.FixtureMergeEnv(map[string]string{ "SOONG_SDK_SNAPSHOT_VERSION": "unversioned", }), ).RunTest(t) checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk.zip") CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. java_import { name: "myjavalib", prefer: false, visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], jars: ["java/myjavalib.jar"], } `), ) }) t.Run("SOONG_SDK_SNAPSHOT_VERSION=current", func(t *testing.T) { result := android.GroupFixturePreparers( preparer, android.FixtureMergeEnv(map[string]string{ "SOONG_SDK_SNAPSHOT_VERSION": "current", }), ).RunTest(t) checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-current.zip") CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. java_import { name: "mysdk_myjavalib@current", sdk_member_name: "myjavalib", visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], jars: ["java/myjavalib.jar"], } java_import { name: "myjavalib", prefer: false, visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], jars: ["java/myjavalib.jar"], } sdk_snapshot { name: "mysdk@current", visibility: ["//visibility:public"], java_header_libs: ["mysdk_myjavalib@current"], } `), ) }) t.Run("SOONG_SDK_SNAPSHOT_VERSION=2", func(t *testing.T) { result := android.GroupFixturePreparers( preparer, android.FixtureMergeEnv(map[string]string{ "SOONG_SDK_SNAPSHOT_VERSION": "2", }), ).RunTest(t) checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-2.zip") CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. java_import { name: "mysdk_myjavalib@2", sdk_member_name: "myjavalib", visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], jars: ["java/myjavalib.jar"], } sdk_snapshot { name: "mysdk@2", visibility: ["//visibility:public"], java_header_libs: ["mysdk_myjavalib@2"], } `), // A versioned snapshot cannot be used on its own so add the source back in. snapshotTestPreparer(checkSnapshotWithoutSource, android.FixtureWithRootAndroidBp(bp)), ) }) t.Run("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE=S", func(t *testing.T) { result := android.GroupFixturePreparers( prepareForSdkTestWithJava, java.PrepareForTestWithJavaDefaultModules, java.PrepareForTestWithJavaSdkLibraryFiles, java.FixtureWithLastReleaseApis("mysdklibrary"), android.FixtureWithRootAndroidBp(` sdk { name: "mysdk", bootclasspath_fragments: ["mybootclasspathfragment"], } bootclasspath_fragment { name: "mybootclasspathfragment", apex_available: ["myapex"], contents: ["mysdklibrary"], } java_sdk_library { name: "mysdklibrary", srcs: ["Test.java"], compile_dex: true, public: {enabled: true}, permitted_packages: ["mysdklibrary"], } `), android.FixtureMergeEnv(map[string]string{ "SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": "S", }), ).RunTest(t) CheckSnapshot(t, result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. prebuilt_bootclasspath_fragment { name: "mybootclasspathfragment", prefer: false, visibility: ["//visibility:public"], apex_available: ["myapex"], contents: ["mysdklibrary"], hidden_api: { annotation_flags: "hiddenapi/annotation-flags.csv", metadata: "hiddenapi/metadata.csv", index: "hiddenapi/index.csv", stub_flags: "hiddenapi/stub-flags.csv", all_flags: "hiddenapi/all-flags.csv", }, } java_sdk_library_import { name: "mysdklibrary", prefer: false, visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], shared_library: true, compile_dex: true, permitted_packages: ["mysdklibrary"], public: { jars: ["sdk_library/public/mysdklibrary-stubs.jar"], stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"], current_api: "sdk_library/public/mysdklibrary.txt", removed_api: "sdk_library/public/mysdklibrary-removed.txt", sdk_version: "current", }, } `), checkAllCopyRules(` .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv .intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt `), ) }) }