summaryrefslogtreecommitdiff
path: root/apex/classpath_element_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'apex/classpath_element_test.go')
-rw-r--r--apex/classpath_element_test.go317
1 files changed, 317 insertions, 0 deletions
diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go
new file mode 100644
index 000000000..0193127b8
--- /dev/null
+++ b/apex/classpath_element_test.go
@@ -0,0 +1,317 @@
+// Copyright (C) 2021 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 apex
+
+import (
+ "reflect"
+ "testing"
+
+ "android/soong/android"
+ "android/soong/java"
+ "github.com/google/blueprint"
+)
+
+// Contains tests for java.CreateClasspathElements logic from java/classpath_element.go that
+// requires apexes.
+
+// testClasspathElementContext is a ClasspathElementContext suitable for use in tests.
+type testClasspathElementContext struct {
+ testContext *android.TestContext
+ module android.Module
+ errs []error
+}
+
+func (t *testClasspathElementContext) OtherModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool {
+ return t.testContext.ModuleHasProvider(module, provider)
+}
+
+func (t *testClasspathElementContext) OtherModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{} {
+ return t.testContext.ModuleProvider(module, provider)
+}
+
+func (t *testClasspathElementContext) ModuleErrorf(fmt string, args ...interface{}) {
+ t.errs = append(t.errs, t.testContext.ModuleErrorf(t.module, fmt, args...))
+}
+
+var _ java.ClasspathElementContext = (*testClasspathElementContext)(nil)
+
+func TestCreateClasspathElements(t *testing.T) {
+ preparer := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ prepareForTestWithArtApex,
+ prepareForTestWithMyapex,
+ // For otherapex.
+ android.FixtureMergeMockFs(android.MockFS{
+ "system/sepolicy/apex/otherapex-file_contexts": nil,
+ }),
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("foo", "othersdklibrary"),
+ android.FixtureWithRootAndroidBp(`
+ apex {
+ name: "com.android.art",
+ key: "com.android.art.key",
+ bootclasspath_fragments: [
+ "art-bootclasspath-fragment",
+ ],
+ java_libs: [
+ "othersdklibrary",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "com.android.art.key",
+ public_key: "com.android.art.avbpubkey",
+ private_key: "com.android.art.pem",
+ }
+
+ bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
+ apex_available: [
+ "com.android.art",
+ ],
+ contents: [
+ "baz",
+ "quuz",
+ ],
+ }
+
+ java_library {
+ name: "baz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ installable: true,
+ }
+
+ java_library {
+ name: "quuz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ installable: true,
+ }
+
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: [
+ "mybootclasspath-fragment",
+ ],
+ java_libs: [
+ "othersdklibrary",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ bootclasspath_fragment {
+ name: "mybootclasspath-fragment",
+ apex_available: [
+ "myapex",
+ ],
+ contents: [
+ "bar",
+ ],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ permitted_packages: ["bar"],
+ }
+
+ java_sdk_library {
+ name: "foo",
+ srcs: ["b.java"],
+ }
+
+ java_sdk_library {
+ name: "othersdklibrary",
+ srcs: ["b.java"],
+ shared_library: false,
+ apex_available: [
+ "com.android.art",
+ "myapex",
+ ],
+ }
+
+ bootclasspath_fragment {
+ name: "non-apex-fragment",
+ contents: ["othersdklibrary"],
+ }
+
+ apex {
+ name: "otherapex",
+ key: "otherapex.key",
+ java_libs: [
+ "otherapexlibrary",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "otherapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "otherapexlibrary",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["otherapex"],
+ permitted_packages: ["otherapexlibrary"],
+ }
+
+ platform_bootclasspath {
+ name: "myplatform-bootclasspath",
+
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+ }
+ `),
+ )
+
+ result := preparer.RunTest(t)
+
+ artFragment := result.Module("art-bootclasspath-fragment", "android_common_apex10000")
+ artBaz := result.Module("baz", "android_common_apex10000")
+ artQuuz := result.Module("quuz", "android_common_apex10000")
+
+ myFragment := result.Module("mybootclasspath-fragment", "android_common_apex10000")
+ myBar := result.Module("bar", "android_common_apex10000")
+
+ nonApexFragment := result.Module("non-apex-fragment", "android_common")
+ other := result.Module("othersdklibrary", "android_common_apex10000")
+
+ otherApexLibrary := result.Module("otherapexlibrary", "android_common_apex10000")
+
+ platformFoo := result.Module("quuz", "android_common")
+
+ bootclasspath := result.Module("myplatform-bootclasspath", "android_common")
+
+ // Use a custom assertion method instead of AssertDeepEquals as the latter formats the output
+ // using %#v which results in meaningless output as ClasspathElements are pointers.
+ assertElementsEquals := func(t *testing.T, message string, expected, actual java.ClasspathElements) {
+ if !reflect.DeepEqual(expected, actual) {
+ t.Errorf("%s: expected:\n %s\n got:\n %s", message, expected, actual)
+ }
+ }
+
+ expectFragmentElement := func(module android.Module, contents ...android.Module) java.ClasspathElement {
+ return &java.ClasspathFragmentElement{module, contents}
+ }
+ expectLibraryElement := func(module android.Module) java.ClasspathElement {
+ return &java.ClasspathLibraryElement{module}
+ }
+
+ newCtx := func() *testClasspathElementContext {
+ return &testClasspathElementContext{testContext: result.TestContext, module: bootclasspath}
+ }
+
+ // Verify that CreateClasspathElements works when given valid input.
+ t.Run("art:baz, art:quuz, my:bar, foo", func(t *testing.T) {
+ ctx := newCtx()
+ elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, artQuuz, myBar, platformFoo}, []android.Module{artFragment, myFragment})
+ expectedElements := java.ClasspathElements{
+ expectFragmentElement(artFragment, artBaz, artQuuz),
+ expectFragmentElement(myFragment, myBar),
+ expectLibraryElement(platformFoo),
+ }
+ assertElementsEquals(t, "elements", expectedElements, elements)
+ })
+
+ // Verify that CreateClasspathElements detects when a fragment does not have an associated apex.
+ t.Run("non apex fragment", func(t *testing.T) {
+ ctx := newCtx()
+ elements := java.CreateClasspathElements(ctx, []android.Module{}, []android.Module{nonApexFragment})
+ android.FailIfNoMatchingErrors(t, "fragment non-apex-fragment{.*} is not part of an apex", ctx.errs)
+ expectedElements := java.ClasspathElements{}
+ assertElementsEquals(t, "elements", expectedElements, elements)
+ })
+
+ // Verify that CreateClasspathElements detects when an apex has multiple fragments.
+ t.Run("multiple fragments for same apex", func(t *testing.T) {
+ ctx := newCtx()
+ elements := java.CreateClasspathElements(ctx, []android.Module{}, []android.Module{artFragment, artFragment})
+ android.FailIfNoMatchingErrors(t, "apex com.android.art has multiple fragments, art-bootclasspath-fragment{.*} and art-bootclasspath-fragment{.*}", ctx.errs)
+ expectedElements := java.ClasspathElements{}
+ assertElementsEquals(t, "elements", expectedElements, elements)
+ })
+
+ // Verify that CreateClasspathElements detects when a library is in multiple fragments.
+ t.Run("library from multiple fragments", func(t *testing.T) {
+ ctx := newCtx()
+ elements := java.CreateClasspathElements(ctx, []android.Module{other}, []android.Module{artFragment, myFragment})
+ android.FailIfNoMatchingErrors(t, "library othersdklibrary{.*} is in two separate fragments, art-bootclasspath-fragment{.*} and mybootclasspath-fragment{.*}", ctx.errs)
+ expectedElements := java.ClasspathElements{}
+ assertElementsEquals(t, "elements", expectedElements, elements)
+ })
+
+ // Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and
+ // are separated by a library from another fragment.
+ t.Run("discontiguous separated by fragment", func(t *testing.T) {
+ ctx := newCtx()
+ elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, myBar, artQuuz, platformFoo}, []android.Module{artFragment, myFragment})
+ expectedElements := java.ClasspathElements{
+ expectFragmentElement(artFragment, artBaz, artQuuz),
+ expectFragmentElement(myFragment, myBar),
+ expectLibraryElement(platformFoo),
+ }
+ assertElementsEquals(t, "elements", expectedElements, elements)
+ android.FailIfNoMatchingErrors(t, "libraries from the same fragment must be contiguous, however baz{.*} and quuz{os:android,arch:common,apex:apex10000} from fragment art-bootclasspath-fragment{.*} are separated by libraries from fragment mybootclasspath-fragment{.*} like bar{.*}", ctx.errs)
+ })
+
+ // Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and
+ // are separated by a standalone library.
+ t.Run("discontiguous separated by library", func(t *testing.T) {
+ ctx := newCtx()
+ elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, platformFoo, artQuuz, myBar}, []android.Module{artFragment, myFragment})
+ expectedElements := java.ClasspathElements{
+ expectFragmentElement(artFragment, artBaz, artQuuz),
+ expectLibraryElement(platformFoo),
+ expectFragmentElement(myFragment, myBar),
+ }
+ assertElementsEquals(t, "elements", expectedElements, elements)
+ android.FailIfNoMatchingErrors(t, "libraries from the same fragment must be contiguous, however baz{.*} and quuz{os:android,arch:common,apex:apex10000} from fragment art-bootclasspath-fragment{.*} are separated by library quuz{.*}", ctx.errs)
+ })
+
+ // Verify that CreateClasspathElements detects when there a library on the classpath that
+ // indicates it is from an apex the supplied fragments list does not contain a fragment for that
+ // apex.
+ t.Run("no fragment for apex", func(t *testing.T) {
+ ctx := newCtx()
+ elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, otherApexLibrary}, []android.Module{artFragment})
+ expectedElements := java.ClasspathElements{
+ expectFragmentElement(artFragment, artBaz),
+ }
+ assertElementsEquals(t, "elements", expectedElements, elements)
+ android.FailIfNoMatchingErrors(t, `library otherapexlibrary{.*} is from apexes \[otherapex\] which have no corresponding fragment in \[art-bootclasspath-fragment{.*}\]`, ctx.errs)
+ })
+}